Skip to content

Commit

Permalink
1
Browse files Browse the repository at this point in the history
  • Loading branch information
hzqst committed Feb 6, 2024
1 parent f957c72 commit 5e1979a
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 348 deletions.
Binary file removed tools/studiocheck.exe
Binary file not shown.
368 changes: 26 additions & 342 deletions toolsrc/studiocheck/studiocheck.cpp
Original file line number Diff line number Diff line change
@@ -1,369 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <IUtilAssetsIntegrity.h>

typedef unsigned char byte;
typedef float vec_t;
typedef float vec2_t[2];
typedef float vec3_t[3];

#include <studio.h>
void UtilAssetsIntegrity_Init();
void UtilAssetsIntegrity_Shutdown();

int main(int argc, const char **argv)
{
if (argc < 2)
return 0;
{
std::cerr << "[Error] No arg(s) available.\n";
return 1;
}

FILE *fp = fopen(argv[1], "rb");
if (!fp)
{
printf("Error: failed to read file %s\n", argv[1]);
return 0;
std::cerr << "[Error] Failed to read file " << argv[1] << "\n";
return 1;
}

fseek(fp, 0, SEEK_END);
auto size = ftell(fp);
auto bufSize = ftell(fp);
fseek(fp, 0, SEEK_SET);

auto buffer = (byte *)malloc(size);
if (!buffer)
auto buf = (unsigned char *)malloc(bufSize);
if (!buf)
{
printf("Error: failed to allocate 0x%X bytes for %s\n", size, argv[1]);

std::cerr << "[Error] Failed to allocate memory for " << argv[1] << "\n";
fclose(fp);
return 0;
}

fread(buffer, size, 1, fp);
fclose(fp);

if (size < sizeof(studiohdr_t))
{
printf("Error: invalid file size (%d < %d)\n", size, sizeof(studiohdr_t));
free(buffer);
return 0;
}

auto studiohdr = (studiohdr_t *)buffer;

printf("Checking %s\n", studiohdr->name);

if (0 == memcmp((const byte *)&studiohdr->id, "IDSQ", 4))
{
printf("Sequence file %s is ok\n", studiohdr->name);
free(buffer);
return 0;
return 1;
}

if (0 != memcmp((const byte *)&studiohdr->id, "IDST", 4))
{
printf("Error: invalid studiohdr->id\n");
free(buffer);
return 0;
}
UtilAssetsIntegrity_Init();

if(studiohdr->version != 10)
{
printf("Error: invalid studiohdr->version, (%d != %d)\n", studiohdr->version, 10);
free(buffer);
return 0;
}

int total;

if (studiohdr->textureindex)
total = studiohdr->texturedataindex;
else
total = studiohdr->length;

if (studiohdr->textureindex)
{
auto ptexture = (mstudiotexture_t *)((byte *)buffer + studiohdr->textureindex);

if ((byte *)(ptexture + studiohdr->numtextures) < (byte *)buffer)
{
printf("Error: invalid numtextures (%p < %p)\n", (byte *)(ptexture + studiohdr->numtextures), (byte *)buffer);
free(buffer);
return 0;
}

if ((byte *)(ptexture + studiohdr->numtextures) > (byte *)buffer + total)
{
printf("Error: invalid numtextures (%p > %p)\n", (byte *)(ptexture + studiohdr->numtextures), (byte *)buffer + total);
free(buffer);
return 0;
}

auto ptexturedata = (byte *)buffer + studiohdr->texturedataindex;

for (int i = 0; i < studiohdr->numtextures; i++)
{
auto pal = (byte *)buffer + ptexture[i].index;
auto palsize = (ptexture[i].height * ptexture[i].width);

if (pal + palsize < (byte *)buffer)
{
printf("Error: invalid texturedata at texture[%d], (%p < %p)\n", i, pal + palsize, (byte *)buffer);
free(buffer);
return 0;
}

if (pal + palsize > (byte *)buffer + studiohdr->length)
{
printf("Error: invalid texturedata at texture[%d], (%p > %p)\n", i, pal + palsize, (byte *)buffer + studiohdr->length);
free(buffer);
return 0;
}

}

printf("numskinfamilies %d\n", studiohdr->numskinfamilies);
printf("numskinref %d\n", studiohdr->numskinref);

auto pskinref = (short*)((byte*)studiohdr + studiohdr->skinindex);

for (int i = 0; i < studiohdr->numskinfamilies; ++i)
{
pskinref += i * studiohdr->numskinref;

if ((byte*)pskinref < (byte*)buffer)
{
printf("Error: invalid pskinref at pskinref[%d], (%p < %p)\n", i, pskinref, (byte*)buffer);
free(buffer);
return 0;
}

if (((byte*)pskinref + sizeof(short) * studiohdr->numskinref) > (byte*)buffer + studiohdr->length)
{
printf("Error: invalid pskinref at pskinref[%d], (%p > %p)\n", i, ((byte*)pskinref + sizeof(short)), (byte*)buffer + studiohdr->length);
free(buffer);
return 0;
}

for (int j = 0; j < studiohdr->numskinref; ++j)
{
auto skinref = pskinref[j];

printf("skinref[%d][%d]=%d\n", i, j, skinref);

if (skinref < 0 || skinref >= studiohdr->numtextures)
{
printf("Error: invalid skinref value (%d) at pskinref[%d][%d]\n", skinref, i, j);
free(buffer);
return 0;
}
}
}
}

#define CHECK_VAR(a) if ((byte *)(a) < (byte *)buffer)\
{\
printf("Error: invalid "#a##" (%p < %p)\n", (byte *)(a), (byte *)buffer);\
free(buffer);\
return 0;\
}\
if ((byte *)(pbodypart + studiohdr->numbodyparts) > (byte *)buffer + total)\
{\
printf("Error: invalid "#a##" (%p > %p)\n", (byte *)(a), (byte *)buffer + total);\
free(buffer);\
return 0;\
}

auto pbodypart = (mstudiobodyparts_t *)((byte *)studiohdr + studiohdr->bodypartindex);

CHECK_VAR(pbodypart + studiohdr->numbodyparts);

for (int i = 0; i < studiohdr->numbodyparts; ++i)
{
auto psubmodel = (mstudiomodel_t *)((byte *)studiohdr + pbodypart[i].modelindex);

CHECK_VAR(psubmodel + pbodypart[i].nummodels);

for (int j = 0; j < pbodypart[i].nummodels; ++j)
{
auto pmesh = (mstudiomesh_t *)((byte *)studiohdr + psubmodel[j].meshindex);

if(psubmodel[j].nummesh)
CHECK_VAR(pmesh + psubmodel[j].nummesh);

auto pstudioverts = (vec3_t *)((byte *)studiohdr + psubmodel[j].vertindex);
if(psubmodel[j].numverts)
CHECK_VAR(pstudioverts + psubmodel[j].numverts);

auto pstudionorms = (vec3_t *)((byte *)studiohdr + psubmodel[j].normindex);
if(psubmodel[j].numnorms)
CHECK_VAR(pstudionorms + psubmodel[j].numnorms);

auto pvertbone = ((byte *)studiohdr + psubmodel[j].vertinfoindex);
if(psubmodel[j].numverts)
CHECK_VAR(pvertbone + psubmodel[j].numverts);

auto pnormbone = ((byte *)studiohdr + psubmodel[j].norminfoindex);
if(psubmodel[j].numverts)
CHECK_VAR(pnormbone + psubmodel[j].numverts);

if (psubmodel[j].numverts > MAXSTUDIOVERTS)
{
printf("Error: psubmodel[j].numverts (%d) > MAXSTUDIOVERTS (%d)\n", psubmodel[j].numverts, MAXSTUDIOVERTS);
free(buffer);
return 0;
}

for (int k = 0; k < psubmodel[j].nummesh; ++k)
{
auto skinref = pmesh[k].skinref;

printf("skinref value = (%d) at pmesh[%d].skinref\n", skinref, k);

if (skinref < 0 || skinref >= studiohdr->numtextures)
{
printf("Error: invalid skinref value (%d) at pmesh[%d].skinref\n", skinref, k);
free(buffer);
return 0;
}
}

for (int k = 0; k < psubmodel[j].nummesh; ++k)
{
auto ptricmds = (short *)((byte *)studiohdr + pmesh[k].triindex);

/*while (*ptricmds)
{
if ((byte *)(ptricmds + 1) > (byte *)buffer + total)
{
printf("Error: (byte *)(ptricmds + 1) (%p) > (byte *)buffer + total (%p)\n", (byte *)(ptricmds + 1), (byte *)buffer + total);
free(buffer);
return 0;
}
ptricmds++;
}*/

int iii;

while (iii = *(ptricmds++))
{
if (iii < 0)
{
iii = -iii;
}
else
{

}


for (; iii > 0; iii--, ptricmds += 4)
{
if (ptricmds[0] >= 0 && ptricmds[0] < MAXSTUDIOVERTS)
{

}
else
{
printf("Error: invalid ptricmds[0] %d\n", ptricmds[0]);
free(buffer);
return 0;
}
if (ptricmds[1] >= 0 && ptricmds[1] < MAXSTUDIOVERTS)
{

}
else
{
printf("Error: invalid ptricmds[1] %d\n", ptricmds[1]);
free(buffer);
return 0;
}
}
}
}
}
}

auto pseqdesc = (mstudioseqdesc_t *)((byte *)studiohdr + studiohdr->seqindex);

if(studiohdr->numseq)
CHECK_VAR(pseqdesc + studiohdr->numseq);

for (int i = 0; i < studiohdr->numseq; ++i)
{
auto pevent = (mstudioevent_t *)((byte *)studiohdr + pseqdesc[i].eventindex);
if(pseqdesc[i].numevents)
CHECK_VAR(pevent + pseqdesc[i].numevents);

auto panim = (mstudioanim_t *)((byte *)studiohdr + pseqdesc[i].animindex);
if(pseqdesc[i].animindex)
CHECK_VAR(panim + 1);
}

auto pseqgroups = (mstudioseqgroup_t *)((byte *)studiohdr + studiohdr->seqgroupindex);

if (studiohdr->numseqgroups)
CHECK_VAR(pseqgroups + studiohdr->numseqgroups);

auto pbbox = (mstudiobbox_t *)((byte *)studiohdr + studiohdr->hitboxindex);

if (studiohdr->numhitboxes)
CHECK_VAR(pbbox + studiohdr->numhitboxes);

for (int i = 0; i < studiohdr->numhitboxes; ++i)
{
int boneindex = pbbox[i].bone;
if (boneindex < -1 || boneindex >= studiohdr->numbones)
{
printf("Error: invalid bone request at pbbox[%d].bone (%d)\n", i, pbbox[i].bone);
free(buffer);
return 0;
}
}

auto pbones = (mstudiobone_t *)((byte *)studiohdr + studiohdr->boneindex);

if (studiohdr->numbones > MAXSTUDIOBONES)
{
printf("Error: studiohdr->numbones (%d) > MAXSTUDIOBONES (%d)\n", studiohdr->numbones, MAXSTUDIOBONES);
free(buffer);
return 0;
}

if (studiohdr->numbones)
CHECK_VAR(pbones + studiohdr->numbones);

for (int i = 0; i < studiohdr->numbones; ++i)
{
if (pbones[i].parent < -1 || pbones[i].parent >= studiohdr->numbones)
{
printf("Error: invalid bone request at pbones[%d].parent (%d)\n", i, pbones[i].parent);
free(buffer);
return 0;
}
}
fread(buf, bufSize, 1, fp);
fclose(fp);

auto pbonecontroller = (mstudiobonecontroller_t *)((byte *)studiohdr + studiohdr->bonecontrollerindex);
UtilAssetsIntegrityCheckResult_StudioModel checkResult;
auto reason = UtilAssetsIntegrity()->CheckStudioModel(buf, bufSize, &checkResult);

if (studiohdr->numbonecontrollers)
CHECK_VAR(pbonecontroller + studiohdr->numbonecontrollers);
UtilAssetsIntegrity_Shutdown();

for (int i = 0; i < studiohdr->numbonecontrollers; i++)
if (reason != UtilAssetsIntegrityCheckReason::OK)
{
int index = pbonecontroller[i].index;
if (index < 0 || index > 4)
{
printf("Error: invalid bonecontroller request at pbonecontroller[%d].index (%d)\n", i, index);
free(buffer);
return 0;
}

int bone = pbonecontroller[i].bone;
if (bone < -1 || bone >= studiohdr->numbones)
{
printf("Error: invalid bone request at pbonecontroller[%d].bone (%d)\n", i, bone);
free(buffer);
return 0;
}
std::cerr << "[Error] Integrity check failed for " << argv[1] << "\n";
std::cerr << "[Reason] " << checkResult.ReasonStr << "\n";
return 1;
}

printf("Model %s is ok\n", studiohdr->name);
free(buffer);
free(buf);
return 0;
}
Loading

0 comments on commit 5e1979a

Please sign in to comment.