MF_API size_t MFString_URLEncode(char *pDest, const char *pString, const char *pExcludeChars) { size_t sourceLen = MFString_Length(pString); size_t destLen = 0; for(size_t a=0; a<sourceLen; ++a) { int c = (uint8)pString[a]; if(MFIsAlphaNumeric(c) || MFString_Chr("-_.!~*'()", c) || (pExcludeChars && MFString_Chr(pExcludeChars, c))) { if(pDest) pDest[destLen] = (char)c; destLen++; } else if(c == ' ') { if(pDest) pDest[destLen] = '+'; destLen++; } else { if(pDest) destLen += sprintf(pDest + destLen, "%%%02X", c); else destLen += 3; // *** surely this can't write more than 3 chars? '%xx' } } if(pDest) pDest[destLen] = 0; return destLen; }
MF_API const char* MFStr_URLEncodeString(const char *pString, const char *pExcludeChars) { char *pBuffer = &gStringBuffer[gStringOffset]; size_t sourceLen = MFString_Length(pString); size_t destLen = 0; for(size_t a=0; a<sourceLen; ++a) { int c = (uint8)pString[a]; if(MFIsAlphaNumeric(c) || MFString_Chr("-_.!~*'()", c) || (pExcludeChars && MFString_Chr(pExcludeChars, c))) pBuffer[destLen++] = (char)c; else if(c == ' ') pBuffer[destLen++] = '+'; else destLen += sprintf(pBuffer + destLen, "%%%02X", c); } pBuffer[destLen] = 0; gStringOffset += destLen+1; if(gStringOffset >= sizeof(gStringBuffer) - 1024) gStringOffset = 0; return pBuffer; }
MFString& MFString::Trim(bool bFront, bool bEnd, const char *pCharacters) { if(pData) { const char *pSrc = pData->pMemory; size_t offset = 0; // trim start if(bFront) { while(pSrc[offset] && MFString_Chr(pCharacters, pSrc[offset])) ++offset; } size_t count = pData->bytes - offset; // trim end if(bEnd) { const char *pEnd = pSrc + offset + count - 1; while(count && MFString_Chr(pCharacters, *pEnd)) { --count; --pEnd; } } *this = SubStr((int)offset, (int)count); } return *this; }
MF_API int MFFileSystem_MountFujiPath(const char *pMountpoint, const char *pFujiPath, int priority, uint32 flags) { const char *pColon = MFString_Chr(pFujiPath, ':'); if(!pColon) return -1; // not a fuji path. needs a volume name! MFMount *pMount = MFFileSystem_FindVolume(MFStrN(pFujiPath, pColon-pFujiPath)); if(!pMount) return -2; // volume not mounted // get the path // ++pColon; // const char *pNewPath = MFStr("%s%s", pColon, MFString_EndsWith(pColon, "/") ? "" : "/"); MFMount *pNew = (MFMount*)MFHeap_Alloc(sizeof(MFMount) + MFString_Length(pMountpoint) + 1); MFCopyMemory(pNew, pMount, sizeof(MFMount)); pNew->volumeInfo.pVolumeName = (const char*)&pNew[1]; MFString_Copy((char*)pNew->volumeInfo.pVolumeName, pMountpoint); pNew->volumeInfo.priority = priority; pNew->volumeInfo.flags = (pNew->volumeInfo.flags & ~MFMF_DontCacheTOC) | flags; return MFFileSystem_AddVolume(pNew); }
const char* GetMaterialName(const char *pSkin, const char *pSubobjectName) { if(pSkin) { char *pTok = MFString_Chr(pSkin, ','); while(pTok) { char *pT = pTok-1; for(; pT > pSkin && pT[-1] != '\n'; --pT) { } // get subobject name char *pTokTemp = pTok - (uintp)pT; const char *pSubName = MFStrN(pT, (int&)pTokTemp); ++pTok; if(!MFString_CaseCmp(pSubName, pSubobjectName)) { for(pT = pTok; *pT != 0 && *pT != '\r' && *pT != '\n'; ++pT) { } // get texture name pTokTemp = pT - (uintp)pTok; char *pMaterialName = (char*)MFStrN(pTok, (int&)pTokTemp); for(pT = pMaterialName+MFString_Length(pMaterialName); pT > pMaterialName && pT[-1] != '/' && pT[-1] != '\\' && pT[-1] != '\n' && pT[-1] != '\r'; --pT) { } pT[MFString_Length(pT) - 4] = 0; return pT; } pTok = MFString_Chr(pTok, ','); } } return NULL; }
void ParseMD3File(char *pBuffer, uint32 bufferSize, const char *pFilename, const char *pSkin) { int a,b; F3DMeshChunk *pMC = pModel->GetMeshChunk(); F3DSkeletonChunk *pSC = pModel->GetSkeletonChunk(); MD3Header *pHeader = (MD3Header*)pBuffer; // DBGASSERT(pHeader->ident == (('3'<<24) | ('P'<<16) | ('D'<<8) | 'I'), "Invalid MD3 header."); // DBGASSERT(pHeader->version == 15, "Invalid MD3 version."); // DBGASSERT(pHeader->offsetEnd == bufferSize, "Incorrect MD3 Size."); (char*&)pHeader->pTags += (uintp)pBuffer; (char*&)pHeader->pSurfaces += (uintp)pBuffer; // read materials if(pSkin) { char *pT, *pTok = MFString_Chr(pSkin, ','); while(pTok) { ++pTok; for(pT = pTok; *pT != 0 && *pT != '\r' && *pT != '\n'; ++pT) { } // get texture name char *pTT = pT - (uintp)pTok; char *pMaterialName = (char*)MFStrN(pTok, (int&)pTT); for(pT = pMaterialName+MFString_Length(pMaterialName); pT > pMaterialName && pT[-1] != '/' && pT[-1] != '\\' && pT[-1] != '\n' && pT[-1] != '\r'; --pT) { } pT[MFString_Length(pT) - 4] = 0; if(*pT && pModel->GetMaterialChunk()->GetMaterialIndexByName(pT) == -1) { F3DMaterial &mat = pModel->GetMaterialChunk()->materials.push(); mat.name = pT; mat.maps[0] = pT; } pTok = MFString_Chr(pTok, ','); } } // process bones for(a=0; a<pHeader->numTags; a++) { F3DBone &bone = pSC->bones.push(); bone.name = pHeader->pTags[a].tagName; bone.worldMatrix.SetXAxis3(MakeVector(pHeader->pTags[a].rotationMatrix[0][0], pHeader->pTags[a].rotationMatrix[0][1], pHeader->pTags[a].rotationMatrix[0][2])); bone.worldMatrix.SetYAxis3(MakeVector(pHeader->pTags[a].rotationMatrix[1][0], pHeader->pTags[a].rotationMatrix[1][1], pHeader->pTags[a].rotationMatrix[1][2])); bone.worldMatrix.SetZAxis3(MakeVector(pHeader->pTags[a].rotationMatrix[2][0], pHeader->pTags[a].rotationMatrix[2][1], pHeader->pTags[a].rotationMatrix[2][2])); bone.worldMatrix.SetTrans3(MakeVector(pHeader->pTags[a].origin[0], pHeader->pTags[a].origin[1], pHeader->pTags[a].origin[2])); } // process mesh for(a=0; a<pHeader->numSurfaces; a++) { // DBGASSERT(pHeader->pSurfaces->identity == (('3'<<24) | ('P'<<16) | ('D'<<8) | 'I'), "Invalid MD3 surface header."); (char*&)pHeader->pSurfaces->pTextureCoords += (uintp)pHeader->pSurfaces; (char*&)pHeader->pSurfaces->pTriangles += (uintp)pHeader->pSurfaces; (char*&)pHeader->pSurfaces->pVertices += (uintp)pHeader->pSurfaces; F3DSubObject &sub = pMC->subObjects.push(); F3DMaterialSubobject &matSub = sub.matSubobjects[0]; // read subobject name sub.name = pHeader->pSurfaces->surfaceName; // find material info matSub.materialIndex = pModel->GetMaterialChunk()->GetMaterialIndexByName(GetMaterialName(pSkin, sub.name.CStr())); // create one colour (white) sub.colours.resize(1); sub.colours[0] = MFVector::one; // read vertex data sub.uvs.resize(pHeader->pSurfaces->numVertices); sub.positions.resize(pHeader->pSurfaces->numVertices); sub.normals.resize(pHeader->pSurfaces->numVertices); for(b=0; b<pHeader->pSurfaces->numVertices; b++) { sub.uvs[b] = MakeVector(pHeader->pSurfaces->pTextureCoords[b].u, pHeader->pSurfaces->pTextureCoords[b].v); sub.normals[b] = MD3DecodeNormal(pHeader->pSurfaces->pVertices[b].encodedNormal); sub.positions[b] = MakeVector(pHeader->pSurfaces->pVertices[b].x, pHeader->pSurfaces->pVertices[b].y, pHeader->pSurfaces->pVertices[b].z); // scale vertex appropriately.. // sub.positions[b].Mul3(sub.positions[b], 1.0f/6400.0f); sub.positions[b].Mul3(sub.positions[b], 1.0f/64.0f); matSub.vertices[b].colour = 0; matSub.vertices[b].normal = b; matSub.vertices[b].uv[0] = b; matSub.vertices[b].position = b; } // read triangles matSub.triangles.resize(pHeader->pSurfaces->numTriangles); for(b=0; b<pHeader->pSurfaces->numTriangles; b++) { matSub.triangles[b].v[0] = pHeader->pSurfaces->pTriangles[b].indices[0]; matSub.triangles[b].v[1] = pHeader->pSurfaces->pTriangles[b].indices[2]; matSub.triangles[b].v[2] = pHeader->pSurfaces->pTriangles[b].indices[1]; } // skip to next surface (char*&)pHeader->pSurfaces += pHeader->pSurfaces->surfaceSize; } }
MF_API MFFind* MFFileSystem_FindFirst(const char *pSearchPattern, MFFindData *pFindData) { GET_MODULE_DATA(MFFileSystemState); const char *pMountpoint = NULL; MFFind *pFind = NULL; // search for a mountpoint const char *pColon = MFString_Chr(pSearchPattern, ':'); if(pColon) { pMountpoint = MFStrN(pSearchPattern, pColon - pSearchPattern); pSearchPattern = pColon + 1; } MFDebug_Assert(pMountpoint, "A volume name must be specified in the search pattern."); // find the volume MFMount *pMount = MFFileSystem_FindVolume(pMountpoint); if(!pMount) { MFDebug_Warn(2, MFStr("MFFileSystem_FindFirst: Volume '%s' in not mounted.", pMountpoint)); return NULL; } // search for file through the mount list... if(!(pMount->volumeInfo.flags & MFMF_DontCacheTOC)) { if(pMount->numFiles) { pFind = pModuleData->gFinds.Create(); pFind->pMount = pMount; MFString_Copy(pFind->searchPattern, pSearchPattern); size_t file = 0; for(; file < pFind->pMount->numFiles; ++file) { if(MFString_PatternMatch(pSearchPattern, pMount->pEntries[file].pName)) break; } if(file == pFind->pMount->numFiles) { pModuleData->gFinds.Destroy(pFind); pFind = NULL; } else { pFind->pFilesystemData = (void*)file; MFString_Copy(pFindData->pFilename, pMount->pEntries[file].pName); MFString_Copy(pFindData->pSystemPath, (char*)pMount->pEntries[file].pFilesysData); pFindData->info = pMount->pEntries[file].info; } } } else { pFind = pModuleData->gFinds.Create(); pFind->pMount = pMount; pFind->pFilesystemData = NULL; MFString_Copy(pFind->searchPattern, pSearchPattern); if(!pModuleData->ppFileSystemList[pMount->volumeInfo.fileSystem]->callbacks.FindFirst(pFind, pSearchPattern, pFindData)) { pModuleData->gFinds.Destroy(pFind); pFind = NULL; } } return pFind; }