for (int i = 0; i < length; i++)
{
data[i] = data[i] ^ magic[i % 257] ^ 0x7B;
}
using System;
using System.IO;
using System.Windows.Forms;
namespace BF3_TOC_CRYPTER
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Title = "Select a .toc file to decrypt...";
open.Filter = "TOC Files|*.toc";
if (open.ShowDialog() == DialogResult.OK)
{
byte[] tocBytes = File.ReadAllBytes(open.FileName);
byte[] magic = new byte[4];
byte[] hash = new byte[256];
byte[] xortable = new byte[257];
byte[] data = new byte[tocBytes.Length - 556];
Buffer.BlockCopy(tocBytes, 0, magic, 0, magic.Length);
if (magic[0] == 0x00 && magic[1] == 0xD1 && magic[2] == 0xCE && magic[3] == 0x00)
{
Buffer.BlockCopy(tocBytes, 8, hash, 0, hash.Length);
Buffer.BlockCopy(tocBytes, 296, xortable, 0, xortable.Length);
Buffer.BlockCopy(tocBytes, 556, data, 0, data.Length);
for (int i = 0; i < data.Length; i++)
{
data[ i ] = Convert.ToByte(data[ i ] ^ xortable[i%257] ^ 0x7b);
}
Buffer.BlockCopy(data, 0, tocBytes, 556, data.Length);
File.WriteAllBytes(open.FileName, tocBytes);
MessageBox.Show("Complete");
}
else
{
MessageBox.Show("Not a valid BF3 .toc file");
}
}
}
}
}
Server.AdministrationServerNameRestricted
Server.AdministrationPassword
Server.RemoteAdministrationPort
Game.Name
Game.MaxPlayerCount
Game.MaxSpectatorCount
Game.LogFileEnable
Game.LogFileCollisionMode
Game.LogFileRotationHistoryLength
Game.Level
Game.ResourceRefreshAlwaysAllowed
Game.InputConfiguration
Game.DefaultTeamId
Game.UseSpeedBasedDetailedCollision
Game.UseSingleWeaponSelector
Game.Platform
Game.AutoAimEnabled
Game.PS3ContentRatingAge
Game.HasUnlimitedAmmo
Game.HasUnlimitedMags
Game****tateLogs
Game.LogHistory
Game.AdjustVehicleCenterOfMass
Game.Version
Game.LayerInclusionTable
Game.DefaultLayerInclusion
Game.TimeBeforeSpawnIsAllowed
Game.LevelWarmUpTime
Game.EnableLoadingProfile
Game.TimeToWaitForQuitTaskCompletion
Game.Player
Game.SoldierWeaponSwitching
Game.DifficultySettings
Game.DifficultyIndex
Game.MetadataContainers
Game.AimAssistEnabled
Game.AimAssistUsePolynomials
Game.ForceFreeStreaming
Game.ForceDisableFreeStreaming
Game.IsGodMode
Game.IsJesusMode
Game.IsGodMode
Game.IsJesusMode
Game.IsJesusModeAi
Game.CurrentSKU
Game.GameAdministrationEnabled
Game.AllowDestructionOutsideCombatArea
Game.DisableDestructionAndDamage
Client.Name
Client.IsSpectator
Client.VsyncEnable
Client.VisualFrameInterpolation
Client.OccludersEnabled
Client.DebrisClusterEnabled
Client.VegetationEnabled
Client.WorldRenderEnabled
Client.TerrainEnabled
Client.WaterPhysicsEnabled
Client.OvergrowthEnabled
Client.EffectsEnabled
Client.EmittersEnabled
Client.PadRumbleEnabled
Client.LipSyncEnabled
Client.OnDamageSpottingEnabled
Client.IgnoreClientFireRateMultiplier
Client.PauseGameOnStartUp
Client.SkipFastLevelLoad
Client.InputEnable
Client.ScreenshotToFile
Client.Screens*******name
Client.ScreenshotSuffix
Client.LoadMenu
Client.IsPresenceEnabled
Client.DebugMenuOnLThumb
Client.InvertFreeCamera
Client.RenderTags
Client.Team
Client.SpawnPointIndex
Client.ServerIp
Client.SecondaryServerIp
Client.InvertPitch
Client.InvertPadPcRightStick
Client.Scheme0FlipY
Client.Scheme1FlipY
Client.Scheme2FlipY
Client.InvertYaw
Client.AimScale
Client.PcPadDeadZone
Client.IsInternetSimulationEnabled
Client.MinLatency
Client.MaxLatency
Client.MinIncomingLatency
Client.MaxIncomingLatency
Client.PacketDrops
Client.DropSpikeChance
Client.MinDropDuration
Client.MaxDropDuration
Client.ReorderingChance
Client.DuplicationChance
Client.CorruptionChance
Client.HavokVisualDebugger
Client.HavokVDBShowsEffectsWorld
Client.HavokCaptureToFile
Client.UseMouseAndKeyboardSystem
Client.UseGlobalGamePadInput
Client.ThreadedLoadingEnable
Client.ShowBuildId
Client.ExtractPersistenceInformation
Client.EnableRestTool
Client.LocalVehicleSimulationEnabled
Client.AsyncClientBulletEntity
Client.AutoUnspawnDynamicObjects
Client.IncomingFrequency
Client.IncomingRate
Client.OutgoingRate
Client.LoadingTimeout
Client.LoadedTimeout
Client.IngameTimeout
Client.QuitGameOnServerDisconnect
UI.Name
UI.System
UI.Bundles
UI.ProfileOptions
UI.Language
UI.EnabledLanguages
UI.OneBundlePerGraph
Network.ProtocolVersion
Network.TitleId
Network.ClientPort
Network.ServerPort
Network.MaxGhostCount
Network.MaxClientCount
Network.MaxClientFrameSize
Network.MaxServerFrameSize
Network.XlspAddress
Network.ServerAddress
Network.ClientConnectionDebugFilePrefix
Network.ServerConnectionDebugFilePrefix
Network.TimeNudgeGhostFrequencyFactor
Network.TimeNudgeBias
Network.IncrementServerPortOnFail
Network.UseFrameManager
Network.TimeSyncEnabled
Network.ConnectTimeout
Demo.RecordDemoFileName
Demo.PlaybackDemoFileName
Demo.TimeDemo
Demo.LockToPlayerName
Demo.ForcedDeltaTickCount
Demo.StartProfilingOnFrame
Demo.StopProfilingOnFrame
Demo.PauseOnStartup
Demo.AllowOverwrite
Demo.LogPerformance
Demo.SuppressDebugLog
Demo.ShutdownOnDemoComplete
Demo.LoopingDemo
Demo.TakeScreenshotOnFrame
Physics.Enable
Physics.ClientEffectWorldThreadCount
Physics.ClientWorldThreadCount
Physics.ServerWorldThreadCount
Physics.IntegrateJobCount
Physics.CollideJobCount
Physics.CollideJobCount
Physics.EnableAIRigidBody
Physics.ForestEnable
Physics.EnableJobs
Physics.HeightfieldRSXStreaming
Physics.RemoveRagdollWhenWoken
Physics.RemoveFromWorldOnCollisionOverflow
Physics.SingleStepCharacter
Physics.ForceSingleStepCharacterInSP
Physics.EnableFollowWheelRaycasts
Physics.EnableClientWheelRaycasts
Physics.EnableASyncWheelRaycasts
Physics.UseDelayedWakeUpClient
Physics.UseDelayedWakeUpServer
Physics.SuppressDebrisSpawnUntilReady
PhysicsDebug.DebugHingeConstraints
PhysicsDebug.UsePhysicsCpuTimers
PhysicsDebug.TimingRecursionDepth
PhysicsRender.RenderServer
PhysicsRender.RenderClient
PhysicsRender.RenderEffectWorld
PhysicsRender.RenderStatic
PhysicsRender.RenderDetail
PhysicsRender.RenderGroup
PhysicsRender.RenderUngrouped
PhysicsRender.RenderRagdoll
PhysicsRender.RenderWater
PhysicsRender.RenderPhantoms
PhysicsRender.ViewDistance
PhysicsRender.RenderConstraints
PhysicsRender.RenderSimulationIslands
PhysicsRender.RenderBroadphaseHandles
PhysicsRender.RenderSolidGeometry
PhysicsRender.CollisionSpawnDebug
PhysicsRender.UseShapeCache
PhysicsRender.RenderWorldStats
PhysicsRender.ShowContactsInWorldStats
PhysicsRender.ShowInactiveContactsInWorldStats
PhysicsRender.ShowPhantomsInWorldStats
PhysicsRender.ShowFixedObjectsInWorldStats
PhysicsRender.RenderSpecificPart
Physics.RemoveRagdollWhenWoken
Physics.RemoveFromWorldOnCollisionOverflow
Physics.SingleStepCharacter
Physics.ForceSingleStepCharacterInSP
Physics.EnableFollowWheelRaycasts
Physics.EnableClientWheelRaycasts
Physics.EnableASyncWheelRaycasts
Physics.UseDelayedWakeUpClient
Physics.UseDelayedWakeUpServer
Physics.SuppressDebrisSpawnUntilReady
PhysicsDebug.DebugHingeConstraints
PhysicsDebug.UsePhysicsCpuTimers
PhysicsDebug.TimingRecursionDepth
PhysicsRender.RenderServer
PhysicsRender.RenderClient
PhysicsRender.RenderEffectWorld
PhysicsRender.RenderStatic
PhysicsRender.RenderDetail
PhysicsRender.RenderGroup
PhysicsRender.RenderUngrouped
PhysicsRender.RenderRagdoll
PhysicsRender.RenderWater
PhysicsRender.RenderPhantoms
PhysicsRender.ViewDistance
PhysicsRender.RenderConstraints
PhysicsRender.RenderSimulationIslands
PhysicsRender.RenderBroadphaseHandles
PhysicsRender.RenderSolidGeometry
PhysicsRender.CollisionSpawnDebug
PhysicsRender.UseShapeCache
PhysicsRender.RenderWorldStats
PhysicsRender.ShowContactsInWorldStats
PhysicsRender.ShowInactiveContactsInWorldStats
PhysicsRender.ShowPhantomsInWorldStats
PhysicsRender.ShowFixedObjectsInWorldStats
PhysicsRender.RenderSpecificPart
PhysicsRender.RenderDestructionConnections
PhysicsRender.RenderEntityStats
PhysicsRender.RenderPartBoundingBoxes
PhysicsRender.RenderOnlyBoundingBoxes
Pathfinding.TypesToDrawMask
Pathfinding.DrawPolygonOutline
Pathfinding.DrawFilledPolygons
Pathfinding.DrawConnections
Pathfinding.DrawObstacles
Pathfinding.DrawStats
Pathfinding.DrawMemory
Pathfinding.DrawTimings
Pathfinding.TextStartX
Pathfinding.TextStartY
Pathfinding.TextOffsetY
Pathfinding.ReplayMode
Pathfinding.OriginalPaths
Pathfinding.RandomPositions
Pathfinding.PotentialObstacles
Ant.DisableAnimManagerSceneOps
Ant.DisableAILodFeature
Ant.DisableModelAnimationCulling
Ant.EnableJobs
Ant.MaxAnimatablesPerPoseJob
Ant.RunAsHighPriority
Ant.ReducedInterpolationDistance
Ant.TrajectoryInterpolationDistance
Ant.MaxInterpolationSlots
Ant.MaxSingleBoneInterpolationSlots
Ant.UpdateLoddingEnable
Ant.CheckGiantSoldiers
Ant.UsePA
Ant.UseHIK
Ant.BlockOnJobs
Ant.InterpolatePoses
Ant.AllowVariableTickLength
Ant.UseWeaponFov
Ant.ForcePoseUpdate
Ant.ForceLodDistance
Ant.UseCameraFov
Ant.EnablePA
Ant.ClientEmulatesServer
Ant.UpdateEnable
Ant.EnablePackageCache
Ant.EnableDebugLogFile
Ant.EnablePoseJobs
Ant.DisableAnimManagerSceneOps
Ant.DisableAILodFeature
Ant.DisableModelAnimationCulling
Ant.EnableJobs
Ant.MaxAnimatablesPerPoseJob
Ant.RunAsHighPriority
Ant.ReducedInterpolationDistance
Ant.TrajectoryInterpolationDistance
Ant.MaxInterpolationSlots
Ant.MaxSingleBoneInterpolationSlots
Ant.UpdateLoddingEnable
Ant.CheckGiantSoldiers
Ant.LeanSignalScale
Ant.LeanSignalClamp
Ant.DetailedCollisionSpeedLimit
AntMemory.MemoryPoolSize
AntMemory.SlotMemorySize
AntMemory.NoOnDemandMemorySize
AntMemory.EnableOnDemandLoad
AntMemory.NumberOfGearSlots
AntMemory.StaticResourcePoolSize
AntMemory.StaticResourcePoolAssets
AntMemory.BundleResourcePoolAssets
AntMemory.StaticBundleImportCount
Render.Enable
Render.InactiveSkipFrameCount
Render.JobEnable
Render.BuildJobSyncEnable
Render.DrawInfo
Render.DrawFps
Render.DrawFpsMethod
Render.Fullscreen
Render.ForceVSyncEnable
Render.XenonRingBufferSize
Render.XenonBufferTwoFramesEnable
Render.XenonPresentImmediateThreshold
Render.XenonGammaCompensationEnable
Render.Ps3FrameMainBufferSize
Render.Ps3FrameLocalBufferSize
Render.Ps3LinearFrameCmdBufEnable
Render.Ps3CellMemoryTexturesEnable
Render.GcmHudEnable
Render.Ps3Res1280x704Enable
Render.PerfOverlayEnable
Render.PerfOverlayVisible
Render.PerfOverlayLatestFrameTimeEnable
Render.CameraCutMaxFrameTranslation
Render.EmittersEnable
Render.EntityRenderEnable
Render.MeshMergingEnable
Render.DebugRendererEnable
Render.DebugRenderServiceEnable
Render.InitialClearEnable
Render.GpuProfilerEnable
Render.NearPlane
Render.ViewDistance
Render.ForceFov
Render.FovMultiplier
Render.ForceOrthoViewEnable
Render.ForceOrthoViewSize
Render.ForceSquareOrthoView
Render.DestructionVolumeDrawEnable
Render.EdgeModelsEnable
Render.EdgeModelCastShadowsEnable
Render.EdgeModelDepthBiasEnable
Render.EdgeModelShadowDepthBiasEnable
Render.EdgeModelScreenAreaScale
Render.EdgeModelSpuInstancingEnable
Render.EdgeModelUseMainLodEnable
Render.EdgeModelForceLod
Render.EdgeModelUseLodBox
Render.EdgeModelLodScale
Render.EdgeModelMaxVisibleInstanceCount
Render.EdgeModelCullEnable
Render.EdgeModelFrustumCullEnable
Render.EdgeModelOcclusionCullEnable
Render.EdgeModelAdditionalCullEnable
Render.EdgeModelDrawBoxes
Render.EdgeModelDrawStats
Render.StaticModelEnable
Render.StaticModelMeshesEnable
Render.StaticModelZPassEnable
Render.StaticModelPartCullEnable
Render.StaticModelPartFrustumCullEnable
Render.StaticModelPartOcclusionCullEnable
Render.StaticModelPartShadowCullEnable
Render.StaticModelDrawBoxes
Render.StaticModelDrawStats
Render.StaticModelPartOcclusionMaxScreenArea
Render.StaticModelCullJobCount
Render.StaticModelCullSpuJobEnable
Render.LockView
Render.ResetLockedView
Render.SplitScreenTestViewCount
Render.FadeEnable
Render.FadeWaitingEnable
Render.ForceBlurAmount
Render.ForceWorldFadeAmount
Render.BlurEnable
Entity.Name
Entity.EditorGameViewEnable
Entity.SpawnSubLevelsFromLogic
Entity.ExecutionMode
subLevel.streamInServer
BugManager.submitBug
BugManager.getOSInfo
BugManager.getReportedBy
BugManager.getChangelist
BugManager.getPlatform
BugManager.getFrostbiteChangelist
BugManager.getJuiceSessionId
presenceTest.setMode
presenceTest.setController
presenceTest.getNewsTicker
presenceTest.downloadUpdate
presenceTest.startMatchmaking
presenceTest.joinGame
presenceTest.claimReservation
presenceTest.getFriends
presenceTest.joinFriend
presenceTest.setPeerMode
presenceTest.completeMission
presenceTest.createPlaygroup
presenceTest.joinPlaygroupByInviteToken
presenceTest.leavePlaygroup
presenceTest.kickFromPlaygroup
presenceTest.getBucketUnlocks
presenceTest.getRankUnlocks
presenceTest.getWeaponUnlocks
presenceTest.requestEorStats
presenceTest.setLocalStat
presenceTest.getClientMPStat
presenceTest.getLeaderboard
presenceTest.setUserInfoAttribute
presenceTest.setUserSetting
presenceTest.getUserSetting
presenceTest.uploadBlob
presenceTest.downloadBlob
presenceTest.fakeFinalize
presenceTest.reportServerBanner
presenceTest.getBestWeaponAndVehicle
serverDestruction.destroyLevel
ServerMetrics.Enabled
ServerMetrics.ReportName
ServerMetrics.TickTelemetryEnabled
ServerMetrics.DevelopmentTelemetryEnabled
ServerMetrics.PerformanceTelemetryEnabled
ServerMetrics.JuiceTelemetryEnabled
ServerMetrics.PerformanceProfileStateEnabled
ServerMetrics.TransactionTelemetryEnabled
ServerMetrics.CompressTransactions
ClientMetrics.Enabled
server.finishGame
server.autoRestartLevel
server.startNextLevel
server.autoStartNextLevel
server.endRound
server.spawnSoldier
server.spawnVehicle
server.spawnSoldierInVehicle
server.setPlayerTeam
server.setPlayerSquad
server.setPlayerTeamAndSquad
server.setPlayerGroupId
server.loadNextLevel
server.addLevel
server.removeLevel
server.listLevels
server.say
server.getServerPort
server.getServerAddress
server.getCurrentConnections
server.getStartPoints
server.getDebugMenuItems
server.triggerDebugMenuItem
ServerPerformanceTracker.reset
TimingView.DrawBarsEnable
TimingView.DrawLegendEnable
TimingView.DrawCpuLegendEnable
TimingView.DrawGpuLegendEnable
TimingView.DrawSpuLegendEnable
TimingView.SnoopEnable
TimingView.SnoopOnly
TimingView.SnoopEventName
TimingView.FilterEnable
TimingView.FilterEventName
TimingView.BarMinTime
TimingView.BarHeight
server.setPlayerTeamAndSquad
server.setPlayerGroupId
server.deletePlayer
server.playerEnterClosestVehicle
server.playerEnterClosestSoldier
server.damageSelf
server.damageSelfFromPlayer
server.damageSoldier
server.damageVehicle
server.setGodMode
server.setJesusModeAi
server.setTickets
server.forceMaxKillCount
server.resetTicketCounters
jobhandler.Reload
MultiProfiler.report
MultiProfiler.reportMin
TimingView.Enable
TimingView.FrameCount
TimingView.FrameDelayCount
TimingView.TimeRange
TimingView.TimeOffset
TimingView.AutolockThreshold
TimingView.LegendScreenOffset
TimingView.LegendColumnWidth
TimingView.LegendDisplayMode
TimingView.AverageFrameCount
TimingView.DrawEnable
TimingView.DrawOnlySummaryEnable
TimingView.DrawBarsEnable
TimingView.DrawLegendEnable
TimingView.DrawCpuLegendEnable
TimingView.DrawGpuLegendEnable
TimingView.DrawSpuLegendEnable
TimingView.SnoopEnable
TimingView.SnoopOnly
TimingView.SnoopEventName
TimingView.FilterEnable
TimingView.FilterEventName
TimingView.BarMinTime
TimingView.BarHeight
TimingView.BarPad
TimingView.BarSyncProcessor
TimingView.GpuBarFrameOffset
TimingView.MaxCpuLegendColumnCount
TimingView.MaxGpuLegendColumnCount
TimingView.MaxSpuLegendColumnCount
TimingView.MaxFrameEventCount
TimingView.reset
TimingView.lock
TimingView.report
server.executeLuaCommand
server.executeLuaScriptFile
server.banPlayer
server.unbanPlayer
server.setServerName
server.kickPlayer
server.listBans
server.loadNextLevel
server.addLevel
server.removeLevel
server.listLevels
server.say
server.getServerPort
server.getServerAddress
server.getCurrentConnections
server.getStartPoints
server.getDebugMenuItems
server.triggerDebugMenuItem
ServerPerformanceTracker.reset
ServerPerformanceTracker.send
ServerPerformanceTracker.sendAfter
ServerBackend.getGameId
voiceRouter.setPlayerVoiceChannel
ServerAdmin.command
ServerAwardSystem.trackAward
ServerAwardSystem.giveAward
ServerAwardSystem.fakeKills
PointSystem.givePoints
PointSystem.setRanks
storage.finalize
DebugMenu.toggleDebugMode
DebugMenu.showMenu
DebugMenuCameraUtil.moveCameraToLocalPlayer
DebugMenuCameraUtil.moveLocalPlayerToCamera
DebugMenuCameraUtil.cameraLookFromRight
DebugMenuCameraUtil.cameraLookFromLeft
DebugMenuCameraUtil.cameraLookFromFront
DebugMenuCameraUtil.cameraLookFromBack
DebugMenuCameraUtil.selectCamera
DebugMenuCameraUtil.setFreeFly
DebugMenuCameraUtil.moveToNextPlayer
DebugMenuCameraUtil.moveToPrevPlayer
TerrainStreaming.DataLoadJobCount
TerrainStreaming.ActiveFreeStreamingDataLoadJobCount
TerrainStreaming.LoadOccluderDataEnable
TerrainStreaming.AdditionalBlurriness
TerrainStreaming.InvisibleDetailReductionFactor
TerrainStreaming.OccludedDetailReductionFactor
TerrainStreaming.KeepPoolFullEnable
TerrainStreaming.HeightfieldAtlasSampleCountXFactor
TerrainStreaming.HeightfieldAtlasSampleCountYFactor
TerrainStreaming.MaskAtlasSampleCountXFactor
TerrainStreaming.MaskAtlasSampleCountYFactor
TerrainStreaming.MaskAdditionalBlurriness
TerrainStreaming.ColorAtlasSampleCountXFactor
TerrainStreaming.ColorAtlasSampleCountYFactor
TerrainStreaming.ColorAdditionalBlurriness
Terrain.HeightQueryCacheSize
Terrain.ModifiersEnable
Terrain.ModifiersCapacity
Terrain.IntersectingModifiersMax
server.loadLevel
server.restartLevel
server.quit
server.saveGame
server.loadGame
server.destroyLevel
server.spawnExplosion
server.healLevel
server.spawnDestructionSphere
server.spawnGameEntity
server.getPlayerCount
server.moveSelf
server.reviveSelf
server.movePlayer
server.dumpStaticHavokGeometry
server.setActiveHealthState
server.writeServerPhysicsWorldInformation
server.dumpServerPhysicsWorldSnapshot
server.startMayaAnimRecording
server.stopMayaAnimRecording
demo.restartPlaybackAtFrame
physics.HavokManagerConsole::dumpHavokProfile
physics.HavokManagerConsole::activateWorld
physics.HavokManagerConsole::dumpHavokMemory
DebrisSystem.Enable
DebrisSystem.TimeScale
DebrisSystem.EnableJobs
DebrisSystem.DrawStats
DebrisSystem.MeshRenderingEnable
DebrisSystem.MeshHavokRenderingEnable
DebrisSystem.MeshDrawTransforms
DebrisSystem.MeshDrawBoundingBoxes
DebrisSystem.MeshShadowEnable
DebrisSystem.MeshViewCullingEnable
DebrisSystem.MeshCullingDistance
DebrisSystem.MeshDrawCountLimit
DebrisSystem.MeshStreamingPriorityMultiplier
DebrisSystem.MeshDrawCullStats
VegetationSystem.WindVariation
VegetationSystem.WindVariationRate
VegetationSystem.WindStrength
VegetationSystem.SimulateServerSide
VegetationSystem.DestructionEnabled
VegetationSystem.LocalInfluencesEnabled
VegetationSystem.MaxActiveDistance
VegetationSystem.SimulationMemKbServer
VegetationSystem.SimulationMemKbClient
VegetationSystem.MaxPreSimsPerJob
VegetationSystem.UseShadowLodOffset
VegetationSystem.ShadowMeshEnable
VegetationSystem.ForceShadowLod
VegetationSystem.DissolveEnable
VegetationSystem.Enable
VegetationSystem.TimeScale
VegetationSystem.EnableJobs
VegetationSystem.JobCount
VegetationSystem.DrawNodes
VegetationSystem.DrawEnable
VegetationSystem.BatchDrawEnable
VegetationSystem.JointTensionLimitIndex
VegetationSystem.JointTensionLimit
ant.listSceneOpMatrices
ant.reportPoseCacheHighWatermark
ant.animatableCount
ant.clientSceneOpMatrix
TestPoints.Initialize
TestPoints.Cleanup
TestPoints.SelectNextChain
TestPoints.SelectNextPoint
import string
import sys
from binascii import hexlify
from struct import unpack
import os
from cStringIO import StringIO
#adjust output folder here; you must specify a folder
outputFolder="C:/bf3 files"
try:
#try to print a number as 0.95
from ctypes import *
floatlib = cdll.LoadLibrary("floattostring")
def formatfloat(num):
bufType = c_char * 100
buf = bufType()
bufpointer = pointer(buf)
floatlib.convertNum(c_double(num), bufpointer, 100)
rawstring=(buf.raw)[:buf.raw.find("\x00")]
if rawstring[:2]=="-.": return "-0."+rawstring[2:]
elif rawstring[0]==".": return "0."+rawstring[1:]
elif "e" not in rawstring and "." not in rawstring: return rawstring+".0"
return rawstring
except:
#the number will be printed as 0.949999988079
def formatfloat(num):
return str(num)
def hasher(keyword): #32bit FNV-1 hash with FNV_offset_basis = 5381 and FNV_prime = 33
hash = 5381
for byte in keyword:
hash = (hash*33) ^ ord(byte)
return hash & 0xffffffff # use & because Python promotes the num instead of intended overflow
class Header:
def __init__(self,varList): ##all 4byte unsigned integers
self.absStringOffset = varList[0] ## absolute offset for string section start
self.lenStringToEOF = varList[1] ## length from string section start to EOF
self.numGUID = varList[2] ## number of external GUIDs
self.null = varList[3] ## 00000000
self.numInstanceRepeater = varList[4]
self.numComplex = varList[5] ## number of complex entries
self.numField = varList[6] ## number of field entries
self.lenName = varList[7] ## length of name section including padding
self.lenString = varList[8] ## length of string section including padding
self.numArrayRepeater = varList[9]
self.lenPayload = varList[10] ## length of normal payload section; the start of the array payload section is absStringOffset+lenString+lenPayload
class FieldDescriptor:
#field has 4byte hash, 2byte type, 2byte reference/pointer, 4byte offset , 4byte secondary offset
#e.g. 4B1F9065 3500 0000 0C000000 1C000000
# hash type ref offset offset2
# => 'VoiceOverType', 0x0035, 0, 12, 28
def __init__(self,varList):
self.name = keywordDict[varList[0]]
self.type = varList[1]
self.ref = varList[2] #the field may contain another complex
self.offset = varList[3] #offset in payload section; relative to the complex containing it
self.secondaryOffset = varList[4]
class ComplexDescriptor:
#complex has 4byte hash, 4byte field index, 1byte number of fields, 1byte alignment size, 2byte type, 2byte payload size, 2byte size2
#e.g. 39E97F28 52000000 04 04 3500 5000 0000
# hash fieldIndex num align type size size2
# => 'EntityVoiceOverInfo', 82, 4, 4, 0x0035, 80, 0
def __init__(self,varList):
self.name = keywordDict[varList[0]]
self.fieldStartIndex = varList[1] #the index of the first field belonging to the complex
self.numField = varList[2] #the total number of fields belonging to the complex
self.alignment = varList[3]
self.type = varList[4]
self.size = varList[5] #total length of the complex in the payload section
self.secondarySize = varList[6] #seems deprecated
class InstanceRepeater:
def __init__(self,varList):
self.null = varList[0] #called "internalCount", seems to be always null
self.repetitions = varList[1] #number of instance repetitions
self.complexIndex = varList[2] #index of complex used as the instance
class arrayRepeater:
def __init__(self,varList):
self.offset = varList[0] #offset in array payload section
self.repetitions = varList[1] #number of array repetitions
self.complexIndex = varList[2] #not necessary for extraction
def read(filename):
global f1, f2, externalGUIDList, internalGUIDList, fields, complexes, header, trueFilename, arrayRepeaters, isPrimaryInstance, keywordDict
#check magic
try: f1=open(filename,"rb")
except: return
if f1.read(4)!="\xCE\xD1\xB2\x0F":
f1.close()
return
print filename
header=Header(unpack("11I",f1.read(44)))
trueFilename="" #the cas extractor only guesses a filename which may be incorrect; but I do know how to find out the correct one
#grab the file GUID and its primary instance. Make the hex numbers to string, e.g. 0x4b => "4b"
fileGUID, primaryInstanceGUID = hexlify(f1.read(16)), hexlify(f1.read(16))
#add all GUID pairs to a list. These are external GUIDs so the first GUID is the GUID
#of another file and the second belongs to an instance inside that file (may or may not be primary)
externalGUIDList=[(hexlify(f1.read(16)),hexlify(f1.read(16))) for i in range(header.numGUID)]
#make list of names and make a dictionary hash vs name
keywords=str.split(f1.read(header.lenName),"\x00")
## while len(keywords[-1])==0:
## keywords.pop() #remove the last few empty entries which appeared due to null-padding; not necessary because keywordDict does not mind
keywordDict=dict((hasher(keyword),keyword) for keyword in keywords)
#read all fields and complexes into lists; replace hashes with names instantly
fields=[FieldDescriptor(unpack("IHHII",f1.read(16))) for i in xrange(header.numField)]
complexes=[ComplexDescriptor(unpack("IIBBHHH",f1.read(16))) for i in xrange(header.numComplex)]
#read instanceRepeater and arrayRepeater, each entry consists of 3 unsigned ints
instanceRepeaters=[InstanceRepeater(unpack("3I",f1.read(12))) for i in range(header.numInstanceRepeater)]
while f1.tell()%16!=0: f1.seek(1,1) #padding
arrayRepeaters=[arrayRepeater(unpack("3I",f1.read(12))) for i in range(header.numArrayRepeater)]
#ignore string section and read directly only when necessary. The elements are accessed directly via offset instead of index.
f1.seek(header.absStringOffset+header.lenString)
#START OF PAYLOAD SECTION
##make a list of all internal instance GUID, ignore the actual payload; this way I can instantly replace a payload Guid index with a string
internalGUIDList=[]
for instanceRepeater in instanceRepeaters:
for repetition in xrange(instanceRepeater.repetitions):
internalGUIDList.append(hexlify(f1.read(16)))
f1.seek(complexes[instanceRepeater.complexIndex].size,1)
f1.seek(header.absStringOffset+header.lenString) # go back to start of payload section
##do the same as above, but 1) don't make a list and 2) read the payload
f2=StringIO() #prepare stream to write the output into memory because filename is not known yet
for instanceRepeater in instanceRepeaters:
instance=complexes[instanceRepeater.complexIndex]
for repetition in xrange(instanceRepeater.repetitions):
tabLevel=1
instanceGUID=hexlify(f1.read(16))
startPos=f1.tell()
if instanceGUID==primaryInstanceGUI
f2.write(instance.name+" "+instanceGUID+" #primary instance
")
isPrimaryInstance=True
else:
f2.write(instance.name+" "+instanceGUID+"
")
isPrimaryInstance=False
readComplex(instance,tabLevel)
f1.seek(startPos+instance.size)
f1.close() # the source file is read and everything is in the f2 stream
#create folder, file, etc.
try:
outFilename=os.path.join(outputFolder,trueFilename)+" "+fileGUID+".txt"
if not os.path.isdir(os.path.dirname(outFilename)): os.makedirs(os.path.dirname(outFilename))
f3=open(outFilename,"wb")
f3.write(f2.getvalue())
f3.close()
except:
print "Could not write file "+filename
try: f3.close()
except: pass
f2.close()
##field types sorted by the value of their ref:
##ref==0 ("7d40","0dc1","3dc1","4dc1","5dc1","adc0","bdc0","ddc0","edc0","fdc0","3500"):
## 7d40: 4bytes; string, the value is the offset in the string section
## 0dc1: 4bytes; uint32
## 3dc1: 4bytes; single float
## 4dc1: 8bytes; double float
## 5dc1: 16bytes; GUID, referring to chunk files?
## adc0: 1byte; bool, padded to 4 if no other adc0,bdc0, the same applies to the other <4 bytes values
## bdc0: 1byte; int8
## ddc0: 2bytes; uint16
## edc0: 2bytes; int16
## fdc0: 4bytes; int32
## 3500: 4bytes; GUID index, read as uint32 and the first bit is the isExternal flag. Do >>31 and afterwards use it as the index for the right GUID table
##
##
##ref!=0 ("4100","2900","29d0"):
## 4100: 4bytes; arrayRepeater index
## 2900: 0bytes; complex entry
## 29d0: 0bytes; complex entry
##
##
##ref sometimes 0, sometimes non 0 ("0000","8900"):
## 0000: 0bytes when field within an enum or 8bytes (all nulls) when element of "$" (which indicates inheritance)
## 8900: 4bytes; enum. Find the enum corresponding to the payload value
def readComplex(complex,tabLevel):
#recursive function to read everything
#get the fields for the complex
fieldList=fields[complex.fieldStartIndex : complex.fieldStartIndex+complex.numField]
startPos=f1.tell()
if tabLevel!=1: f2.write("::"+complex.name+"
")
for field in fieldList:
readField(field,startPos,tabLevel)
f1.seek(startPos+complex.size)
def readField(field,startPos,tabLevel):
f1.seek(startPos+field.offset)
## f2.write("@"+str(f1.tell()))
if field.type not in (0x0029,0xd029,0x0041,0x0000): #handle the simple stuff
f2.write(tabLevel*"\t"+field.name+" "+unpackSimpleField(field)+"
")
elif field.type !=0x0041: #non arrays
f2.write(tabLevel*"\t"+field.name)
readComplex(complexes[field.ref],tabLevel+1) #recursion
else: #arrays
arrayIndex=unpack("I",f1.read(4))[0]
if arrayIndex==0: #in contrast to the 0035 type, this time index 0 is reserved for these cases
f2.write(tabLevel*"\t"+field.name+" *nullArray*"+"
")
return
arrayRepeater=arrayRepeaters[arrayIndex] #no arrayIndex-1 necessary
f1.seek(arrayRepeater.offset+header.absStringOffset+header.lenString+header.lenPayload)
if arrayRepeater.repetitions==0: f2.write(tabLevel*"\t"+field.name+" *nullArray*"+"
")
else:
arrayComplex=complexes[field.ref]
memberField=fields[arrayComplex.fieldStartIndex]
f2.write(tabLevel*"\t"+field.name)
f2.write("::"+arrayComplex.name+"
")
for arrayRepetition in xrange(arrayRepeater.repetitions):
position=f1.tell()
readField(memberField,position,tabLevel+1) #recursion
#make a dictionary for the number/bool types. Mainly to save me from bloating the function below too much. Single floats not included either because I want to display them properly.
numDict={0xc10d"I",4),0xc14d"d",,0xc0ad"?",1),0xc0fd"i",4),0xc0bd"b",1),0xc0ed"h",2), 0xc0dd"H",2)}
def unpackSimpleField(field):
#read everything except 0x0029, 0xd029, 0x0041, 0x0000
#i.e. all assignments that do not contain another complex (0x0089 being the exception because it is so different)
global trueFilename
try:
#if the entry is number/bool, extract it with the dictionary; else go to except
(typ,length)=numDict[field.type]
num=unpack(typ,f1.read(length))[0]
return str(num)
except:
if field.type==0xc13d: return formatfloat(unpack("f",f1.read(4))[0])
if field.type==0xc15d: return hexlify(f1.read(16)) #GUID, neither external nor internal
elif field.type==0xc0dd: return hexlify(f1.read(2)) #not sure about this type
elif field.type==0x0089:
if field.ref==0: return "*nullEnum*"
else:
#The field points at another complex. The fields in this complex then are the choices.
#Basically I go through the fields one level deeper. These fields do not behave like actual fields, lots of nulls and offset is no offset at all.
compareValue=unpack("I",f1.read(4))[0] #this value must match fakefield.offset
fieldList=fields[complexes[field.ref].fieldStartIndex : complexes[field.ref].fieldStartIndex+complexes[field.ref].numField]
for fakeField in fieldList:
if fakeField.offset==compareValue:
return fakeField.name
elif field.type==0x407d: #the string section
#The 4bytes payload are the offset, so we need to remember where we are, then jump and read
#a null-terminated string and jump back
originalPos=f1.tell()
f1.seek(header.absStringOffset+unpack("I",f1.read(4))[0])
string=""
while 1:
a=f1.read(1)
if a=="\x00": break
else: string+=a
f1.seek(originalPos+4)
if len(string)==0: return "*nullString*" #actually the string is ""
if isPrimaryInstance and trueFilename=="" and field.name=="Name": trueFilename=string
return string
elif field.type==0x0035:
#Write the GUID of another instance. There are two different cases.
#If the instance is found in another file use externalGUIDList (2*16 bytes).
#If the instance is found in this file use internalGUIDList (1*16 bytes).
#The first bit is the isExternal flag. => bitshift by 31 and bitmask
GUIDIndex=unpack("I",f1.read(4))[0]
if GUIDIndex>>31: return "-".join(externalGUIDList[GUIDIndex&0x7fffffff])
elif GUIDIndex==0: return "*nullGuid*" #this being handled differently by the engine is a bit annoying as internalGUIDList of course has an element at index 0
else: return internalGUIDList[GUIDIndex-1] #as a result, minus 1 is necessary
def main():
if not outputFolder:
return
for ff in sys.argv[1:]:
if os.path.isfile(ff):
read(ff)
else:
for dir0,dirs,files in os.walk(ff):
for f in files:
read(dir0+"\\"+f)
try:
main()
except Exception, e:
raw_input(e)
main()
import string
import sys
from binascii import hexlify
from struct import unpack
import os
from cStringIO import StringIO
#adjust output folder here; you must specify a folder
outputFolder="C:/bf3 files"
try:
#try to print a number as 0.95
from ctypes import *
floatlib = cdll.LoadLibrary("floattostring")
def formatfloat(num):
bufType = c_char * 100
buf = bufType()
bufpointer = pointer(buf)
floatlib.convertNum(c_double(num), bufpointer, 100)
rawstring=(buf.raw)[:buf.raw.find("\x00")]
if rawstring[:2]=="-.": return "-0."+rawstring[2:]
elif rawstring[0]==".": return "0."+rawstring[1:]
elif "e" not in rawstring and "." not in rawstring: return rawstring+".0"
return rawstring
except:
#the number will be printed as 0.949999988079
def formatfloat(num):
return str(num)
def hasher(keyword): #32bit FNV-1 hash with FNV_offset_basis = 5381 and FNV_prime = 33
hash = 5381
for byte in keyword:
hash = (hash*33) ^ ord(byte)
return hash & 0xffffffff # use & because Python promotes the num instead of intended overflow
class Header:
def __init__(self,varList): ##all 4byte unsigned integers
self.absStringOffset = varList[0] ## absolute offset for string section start
self.lenStringToEOF = varList[1] ## length from string section start to EOF
self.numGUID = varList[2] ## number of external GUIDs
self.null = varList[3] ## 00000000
self.numInstanceRepeater = varList[4]
self.numComplex = varList[5] ## number of complex entries
self.numField = varList[6] ## number of field entries
self.lenName = varList[7] ## length of name section including padding
self.lenString = varList[8] ## length of string section including padding
self.numArrayRepeater = varList[9]
self.lenPayload = varList[10] ## length of normal payload section; the start of the array payload section is absStringOffset+lenString+lenPayload
class FieldDescriptor:
#field has 4byte hash, 2byte type, 2byte reference/pointer, 4byte offset , 4byte secondary offset
#e.g. 4B1F9065 3500 0000 0C000000 1C000000
# hash type ref offset offset2
# => 'VoiceOverType', 0x0035, 0, 12, 28
def __init__(self,varList):
self.name = keywordDict[varList[0]]
self.type = varList[1]
self.ref = varList[2] #the field may contain another complex
self.offset = varList[3] #offset in payload section; relative to the complex containing it
self.secondaryOffset = varList[4]
class ComplexDescriptor:
#complex has 4byte hash, 4byte field index, 1byte number of fields, 1byte alignment size, 2byte type, 2byte payload size, 2byte size2
#e.g. 39E97F28 52000000 04 04 3500 5000 0000
# hash fieldIndex num align type size size2
# => 'EntityVoiceOverInfo', 82, 4, 4, 0x0035, 80, 0
def __init__(self,varList):
self.name = keywordDict[varList[0]]
self.fieldStartIndex = varList[1] #the index of the first field belonging to the complex
self.numField = varList[2] #the total number of fields belonging to the complex
self.alignment = varList[3]
self.type = varList[4]
self.size = varList[5] #total length of the complex in the payload section
self.secondarySize = varList[6] #seems deprecated
class InstanceRepeater:
def __init__(self,varList):
self.null = varList[0] #called "internalCount", seems to be always null
self.repetitions = varList[1] #number of instance repetitions
self.complexIndex = varList[2] #index of complex used as the instance
class arrayRepeater:
def __init__(self,varList):
self.offset = varList[0] #offset in array payload section
self.repetitions = varList[1] #number of array repetitions
self.complexIndex = varList[2] #not necessary for extraction
def read(filename):
global f1, f2, externalGUIDList, internalGUIDList, fields, complexes, header, trueFilename, arrayRepeaters, isPrimaryInstance, keywordDict
#check magic
try: f1=open(filename,"rb")
except: return
if f1.read(4)!="\xCE\xD1\xB2\x0F":
f1.close()
return
print filename
header=Header(unpack("11I",f1.read(44)))
trueFilename="" #the cas extractor only guesses a filename which may be incorrect; but I do know how to find out the correct one
#grab the file GUID and its primary instance. Make the hex numbers to string, e.g. 0x4b => "4b"
fileGUID, primaryInstanceGUID = hexlify(f1.read(16)), hexlify(f1.read(16))
#add all GUID pairs to a list. These are external GUIDs so the first GUID is the GUID
#of another file and the second belongs to an instance inside that file (may or may not be primary)
externalGUIDList=[(hexlify(f1.read(16)),hexlify(f1.read(16))) for i in range(header.numGUID)]
#make list of names and make a dictionary hash vs name
keywords=str.split(f1.read(header.lenName),"\x00")
## while len(keywords[-1])==0:
## keywords.pop() #remove the last few empty entries which appeared due to null-padding; not necessary because keywordDict does not mind
keywordDict=dict((hasher(keyword),keyword) for keyword in keywords)
#read all fields and complexes into lists; replace hashes with names instantly
fields=[FieldDescriptor(unpack("IHHII",f1.read(16))) for i in xrange(header.numField)]
complexes=[ComplexDescriptor(unpack("IIBBHHH",f1.read(16))) for i in xrange(header.numComplex)]
#read instanceRepeater and arrayRepeater, each entry consists of 3 unsigned ints
instanceRepeaters=[InstanceRepeater(unpack("3I",f1.read(12))) for i in range(header.numInstanceRepeater)]
while f1.tell()%16!=0: f1.seek(1,1) #padding
arrayRepeaters=[arrayRepeater(unpack("3I",f1.read(12))) for i in range(header.numArrayRepeater)]
#ignore string section and read directly only when necessary. The elements are accessed directly via offset instead of index.
f1.seek(header.absStringOffset+header.lenString)
#START OF PAYLOAD SECTION
##make a list of all internal instance GUID, ignore the actual payload; this way I can instantly replace a payload Guid index with a string
internalGUIDList=[]
for instanceRepeater in instanceRepeaters:
for repetition in xrange(instanceRepeater.repetitions):
internalGUIDList.append(hexlify(f1.read(16)))
f1.seek(complexes[instanceRepeater.complexIndex].size,1)
f1.seek(header.absStringOffset+header.lenString) # go back to start of payload section
##do the same as above, but 1) don't make a list and 2) read the payload
f2=StringIO() #prepare stream to write the output into memory because filename is not known yet
for instanceRepeater in instanceRepeaters:
instance=complexes[instanceRepeater.complexIndex]
for repetition in xrange(instanceRepeater.repetitions):
tabLevel=1
instanceGUID=hexlify(f1.read(16))
startPos=f1.tell()
if instanceGUID==primaryInstanceGUI
f2.write(instance.name+" "+instanceGUID+" #primary instance
")
isPrimaryInstance=True
else:
f2.write(instance.name+" "+instanceGUID+"
")
isPrimaryInstance=False
readComplex(instance,tabLevel)
f1.seek(startPos+instance.size)
f1.close() # the source file is read and everything is in the f2 stream
#create folder, file, etc.
try:
outFilename=os.path.join(outputFolder,trueFilename)+" "+fileGUID+".txt"
if not os.path.isdir(os.path.dirname(outFilename)): os.makedirs(os.path.dirname(outFilename))
f3=open(outFilename,"wb")
f3.write(f2.getvalue())
f3.close()
except:
print "Could not write file "+filename
try: f3.close()
except: pass
f2.close()
##field types sorted by the value of their ref:
##ref==0 ("7d40","0dc1","3dc1","4dc1","5dc1","adc0","bdc0","ddc0","edc0","fdc0","3500"):
## 7d40: 4bytes; string, the value is the offset in the string section
## 0dc1: 4bytes; uint32
## 3dc1: 4bytes; single float
## 4dc1: 8bytes; double float
## 5dc1: 16bytes; GUID, referring to chunk files?
## adc0: 1byte; bool, padded to 4 if no other adc0,bdc0, the same applies to the other <4 bytes values
## bdc0: 1byte; int8
## ddc0: 2bytes; uint16
## edc0: 2bytes; int16
## fdc0: 4bytes; int32
## 3500: 4bytes; GUID index, read as uint32 and the first bit is the isExternal flag. Do >>31 and afterwards use it as the index for the right GUID table
##
##
##ref!=0 ("4100","2900","29d0"):
## 4100: 4bytes; arrayRepeater index
## 2900: 0bytes; complex entry
## 29d0: 0bytes; complex entry
##
##
##ref sometimes 0, sometimes non 0 ("0000","8900"):
## 0000: 0bytes when field within an enum or 8bytes (all nulls) when element of "$" (which indicates inheritance)
## 8900: 4bytes; enum. Find the enum corresponding to the payload value
def readComplex(complex,tabLevel):
#recursive function to read everything
#get the fields for the complex
fieldList=fields[complex.fieldStartIndex : complex.fieldStartIndex+complex.numField]
startPos=f1.tell()
if tabLevel!=1: f2.write("::"+complex.name+"
")
for field in fieldList:
readField(field,startPos,tabLevel)
f1.seek(startPos+complex.size)
def readField(field,startPos,tabLevel):
f1.seek(startPos+field.offset)
## f2.write("@"+str(f1.tell()))
if field.type not in (0x0029,0xd029,0x0041,0x0000): #handle the simple stuff
f2.write(tabLevel*"\t"+field.name+" "+unpackSimpleField(field)+"
")
elif field.type !=0x0041: #non arrays
f2.write(tabLevel*"\t"+field.name)
readComplex(complexes[field.ref],tabLevel+1) #recursion
else: #arrays
arrayIndex=unpack("I",f1.read(4))[0]
if arrayIndex==0: #in contrast to the 0035 type, this time index 0 is reserved for these cases
f2.write(tabLevel*"\t"+field.name+" *nullArray*"+"
")
return
arrayRepeater=arrayRepeaters[arrayIndex] #no arrayIndex-1 necessary
f1.seek(arrayRepeater.offset+header.absStringOffset+header.lenString+header.lenPayload)
if arrayRepeater.repetitions==0: f2.write(tabLevel*"\t"+field.name+" *nullArray*"+"
")
else:
arrayComplex=complexes[field.ref]
memberField=fields[arrayComplex.fieldStartIndex]
f2.write(tabLevel*"\t"+field.name)
f2.write("::"+arrayComplex.name+"
")
for arrayRepetition in xrange(arrayRepeater.repetitions):
position=f1.tell()
readField(memberField,position,tabLevel+1) #recursion
#make a dictionary for the number/bool types. Mainly to save me from bloating the function below too much. Single floats not included either because I want to display them properly.
numDict={0xc10d"I",4),0xc14d"d",,0xc0ad"?",1),0xc0fd"i",4),0xc0bd"b",1),0xc0ed"h",2), 0xc0dd"H",2)}
def unpackSimpleField(field):
#read everything except 0x0029, 0xd029, 0x0041, 0x0000
#i.e. all assignments that do not contain another complex (0x0089 being the exception because it is so different)
global trueFilename
try:
#if the entry is number/bool, extract it with the dictionary; else go to except
(typ,length)=numDict[field.type]
num=unpack(typ,f1.read(length))[0]
return str(num)
except:
if field.type==0xc13d: return formatfloat(unpack("f",f1.read(4))[0])
if field.type==0xc15d: return hexlify(f1.read(16)) #GUID, neither external nor internal
elif field.type==0xc0dd: return hexlify(f1.read(2)) #not sure about this type
elif field.type==0x0089:
if field.ref==0: return "*nullEnum*"
else:
#The field points at another complex. The fields in this complex then are the choices.
#Basically I go through the fields one level deeper. These fields do not behave like actual fields, lots of nulls and offset is no offset at all.
compareValue=unpack("I",f1.read(4))[0] #this value must match fakefield.offset
fieldList=fields[complexes[field.ref].fieldStartIndex : complexes[field.ref].fieldStartIndex+complexes[field.ref].numField]
for fakeField in fieldList:
if fakeField.offset==compareValue:
return fakeField.name
elif field.type==0x407d: #the string section
#The 4bytes payload are the offset, so we need to remember where we are, then jump and read
#a null-terminated string and jump back
originalPos=f1.tell()
f1.seek(header.absStringOffset+unpack("I",f1.read(4))[0])
string=""
while 1:
a=f1.read(1)
if a=="\x00": break
else: string+=a
f1.seek(originalPos+4)
if len(string)==0: return "*nullString*" #actually the string is ""
if isPrimaryInstance and trueFilename=="" and field.name=="Name": trueFilename=string
return string
elif field.type==0x0035:
#Write the GUID of another instance. There are two different cases.
#If the instance is found in another file use externalGUIDList (2*16 bytes).
#If the instance is found in this file use internalGUIDList (1*16 bytes).
#The first bit is the isExternal flag. => bitshift by 31 and bitmask
GUIDIndex=unpack("I",f1.read(4))[0]
if GUIDIndex>>31: return "-".join(externalGUIDList[GUIDIndex&0x7fffffff])
elif GUIDIndex==0: return "*nullGuid*" #this being handled differently by the engine is a bit annoying as internalGUIDList of course has an element at index 0
else: return internalGUIDList[GUIDIndex-1] #as a result, minus 1 is necessary
def main():
if not outputFolder:
return
for ff in sys.argv[1:]:
if os.path.isfile(ff):
read(ff)
else:
for dir0,dirs,files in os.walk(ff):
for f in files:
read(dir0+"\\"+f)
try:
main()
except Exception, e:
raw_input(e)
main()
Copyright © 2024, NextGenUpdate.
All Rights Reserved.