/* ===================================== Cmd_GetConfigList Prints or complete .cfg filename ===================================== */ qboolean Cmd_GetConfigList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numconfigs; t = FS_Search( va( "%s*.cfg", s ), true, false ); if( !t ) return false; Q_strncpy( matchbuf, t->filenames[0], 256 ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, numconfigs = 0; i < t->numfilenames; i++ ) { const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "cfg" )) continue; Q_strncpy( matchbuf, t->filenames[i], 256 ); Msg( "%16s\n", matchbuf ); numconfigs++; } Msg( "\n^3 %i configs found.\n", numconfigs ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ===================================== Cmd_GetSavesList Prints or complete savegame filename ===================================== */ qboolean Cmd_GetSavesList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numsaves; t = FS_Search( va( "save/%s*.sav", s ), true, true ); // lookup only in gamedir if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, numsaves = 0; i < t->numfilenames; i++ ) { const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "sav" )) continue; FS_FileBase( t->filenames[i], matchbuf ); Msg( "%16s\n", matchbuf ); numsaves++; } Msg( "\n^3 %i saves found.\n", numsaves ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ============================= idGameBustOutWindow::LoadBoardFiles ============================= */ void idGameBustOutWindow::LoadBoardFiles( void ) { int i; int w,h; ID_TIME_T time; int boardSize; byte *currentBoard; if ( boardDataLoaded ) { return; } boardSize = 9 * 12 * 4; levelBoardData = (byte*)Mem_Alloc( boardSize * numLevels ); currentBoard = levelBoardData; for ( i=0; i<numLevels; i++ ) { byte *pic; idStr name = "guis/assets/bustout/level"; name += (i+1); name += ".tga"; R_LoadImage( name, &pic, &w, &h, &time, false ); if ( pic != NULL ) { if ( w != 9 || h != 12 ) { common->DWarning( "Hell Bust-Out level image not correct dimensions! (%d x %d)", w, h ); } memcpy( currentBoard, pic, boardSize ); Mem_Free(pic); } currentBoard += boardSize; } boardDataLoaded = true; }
void SW_VES_deconstruct(void) { OutPeriod pd; IntU i; // De-allocate parameters if (SW_VegEstab.count > 0) { for (i = 0; i < SW_VegEstab.count; i++) { Mem_Free(SW_VegEstab.parms[i]); SW_VegEstab.parms[i] = NULL; } Mem_Free(SW_VegEstab.parms); SW_VegEstab.parms = NULL; } ForEachOutPeriod(pd) { // De-allocate days and parameters if (SW_VegEstab.count > 0) { if (!isnull(SW_VegEstab.p_oagg[pd]->days)) { Mem_Free(SW_VegEstab.p_oagg[eSW_Year]->days); } if (!isnull(SW_VegEstab.p_accu[pd]->days)) { Mem_Free(SW_VegEstab.p_accu[eSW_Year]->days); } } // De-allocate output structures if (pd > eSW_Day && !isnull(SW_VegEstab.p_oagg[pd])) { Mem_Free(SW_VegEstab.p_oagg[pd]); SW_VegEstab.p_oagg[pd] = NULL; } if (!isnull(SW_VegEstab.p_accu[pd])) { Mem_Free(SW_VegEstab.p_accu[pd]); SW_VegEstab.p_accu[pd] = NULL; } } }
static unsigned char *decode_image(downloadinfo *di, const char *content_type) { unsigned char *pixels = NULL; fs_offset_t filesize = 0; unsigned char *data = FS_LoadFile(di->filename, tempmempool, true, &filesize); if(data) { int mip = 0; if(!strcmp(content_type, "image/jpeg")) pixels = JPEG_LoadImage_BGRA(data, filesize, &mip); else if(!strcmp(content_type, "image/png")) pixels = PNG_LoadImage_BGRA(data, filesize, &mip); else if(filesize >= 7 && !strncmp((char *) data, "\xFF\xD8", 7)) pixels = JPEG_LoadImage_BGRA(data, filesize, &mip); else if(filesize >= 7 && !strncmp((char *) data, "\x89PNG\x0D\x0A\x1A\x0A", 7)) pixels = PNG_LoadImage_BGRA(data, filesize, &mip); else Con_Printf("Did not detect content type: %s\n", content_type); Mem_Free(data); } // do we call Image_MakeLinearColorsFromsRGB or not? return pixels; }
DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, BYTE count) { void *buffer; u32 len; s32 ret = 0; /* Buffer length */ len = (count * SECTOR_SZ); /* Allocate buffer */ buffer = Mem_Alloc(count * 512); if (!buffer) return RES_ERROR; /* Read sectors */ switch (drv) { case DRIVE_SDHC: /* Read SD sectors */ ret = sdio_ReadSectors(sector, count, buffer); break; case DRIVE_EHCI: /* Read USB sectors */ ret = ehci_ReadSectors(sector, count, buffer); break; } /* Copy buffer */ if (ret) memcpy(buff, buffer, len); /* Free buffer */ Mem_Free(buffer); return (ret) ? RES_OK : RES_ERROR; }
/* * @brief Captures a screenshot, writing it to the user's directory. */ void R_Screenshot_f(void) { static uint16_t last_screenshot; char filename[MAX_OS_PATH]; uint16_t i; // find a file name to save it to for (i = last_screenshot; i < MAX_SCREENSHOTS; i++) { g_snprintf(filename, sizeof(filename), "screenshots/quetoo%03u.jpg", i); if (!Fs_Exists(filename)) break; // file doesn't exist } if (i == MAX_SCREENSHOTS) { Com_Warn("Failed to create %s\n", filename); return; } last_screenshot = i; // save for next call const uint32_t width = r_context.width; const uint32_t height = r_context.height; byte *buffer = Mem_Malloc(width * height * 3); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); const int32_t quality = Clamp(r_screenshot_quality->integer, 0, 100); if (Img_WriteJPEG(filename, buffer, width, height, quality)) { Com_Print("Saved %s\n", Basename(filename)); } else { Com_Warn("Failed to write %s\n", filename); } Mem_Free(buffer); }
void FreeXprt(SVCXPRT *xprt) { if(!xprt) { LogFullDebug(COMPONENT_RPC, "Attempt to free NULL xprt"); return; } LogFullDebug(COMPONENT_RPC, "FreeXprt xprt=%p", xprt); if(xprt->xp_ops == &Svcudp_op) { xp_free(Su_data(xprt)); xp_free(rpc_buffer(xprt)); } else if (xprt->xp_ops == &Svctcp_op) { struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; XDR_DESTROY(&(cd->xdrs)); xp_free(xprt->xp_p1); /* cd */ } else if (xprt->xp_ops == &Svctcp_rendezvous_op) { xp_free(xprt->xp_p1); /* r */ } else { LogCrit(COMPONENT_RPC, "Attempt to free unknown xprt %p", xprt); return; } Mem_Free(xprt); }
/* test the maps that have seedlists */ static void testSeedlists (void) { int i, n; long time, timeSum = 0; MapInfo *randomMap; size_t length; const char* assNames[][2] = { {"farm", "medium"}, {"farm", "large"}, {"forest", "large"}, {"forest", "large_crash"}, {"oriental", "large"}, {"village", "commercial"}, {"village", "small"} }; length = sizeof(assNames) / (2 * sizeof(char *)); char entityString[MAX_TOKEN_CHARS]; sv_threads->integer = 0; for (n = 0; n < length; n++) { for (i = 1; i < 20; i++) { srand(i); time = Sys_Milliseconds(); Com_Printf("Seed: %i\n", i); randomMap = SV_AssembleMap(assNames[n][0], assNames[n][1], mapStr, posStr, entityString, i); CU_ASSERT(randomMap != NULL); time = Sys_Milliseconds() - time; timeSum += time; UFO_CU_ASSERT_TRUE_MSG(time < MAX_ALLOWED_TIME_TO_ASSEMBLE, va("%s fails to assemble in a reasonable time with seed %i (time: %li ms)", randomMap->name, i, time)); if (time > 10000) Com_Printf("Seed %i: tiles: %i ms: %li\n", i, randomMap->numPlaced, time); Mem_Free(randomMap); } } Com_Printf("TotalTime: %li\n", timeSum); }
/* =============== Host_Exec_f =============== */ void Host_Exec_f( void ) { string cfgpath; char *f; if( Cmd_Argc() != 2 ) { Msg( "Usage: exec <filename>\n" ); return; } // HACKHACK: don't execute listenserver.cfg in singleplayer if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 ))) { if( Cvar_VariableValue( "maxplayers" ) == 1.0f ) return; } Q_strncpy( cfgpath, Cmd_Argv( 1 ), sizeof( cfgpath )); FS_DefaultExtension( cfgpath, ".cfg" ); // append as default f = (char *)FS_LoadFile( cfgpath, NULL, false ); if( !f ) { MsgDev( D_NOTE, "couldn't exec %s\n", Cmd_Argv( 1 )); return; } MsgDev( D_INFO, "execing %s\n", Cmd_Argv( 1 )); // terminate the string with newline just in case it's missing // insertion order is backwards from execution order Cbuf_InsertText( "\n" ); Cbuf_InsertText( f ); Mem_Free( f ); }
/* ================ idDemoFile::Close ================ */ void idDemoFile::Close() { if ( writing && compressor ) { compressor->FinishCompress(); } if ( f ) { fileSystem->CloseFile( f ); f = NULL; } if ( fLog ) { fileSystem->CloseFile( fLog ); fLog = NULL; } if ( fileImage ) { Mem_Free( fileImage ); fileImage = NULL; } if ( compressor ) { delete compressor; compressor = NULL; } demoStrings.DeleteContents( true ); }
/** * FSAL_closedir : * Free the resources allocated for reading directory entries. * * \param dir_descriptor (input): * Pointer to a directory descriptor filled by FSAL_opendir. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t POSIXFSAL_closedir(fsal_dir_t * dir_descriptor /* IN */ ) { posixfsal_dir_t * p_dir_descriptor = (posixfsal_dir_t *) dir_descriptor; int rc; /* sanity checks */ if(!p_dir_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_closedir); #ifdef _USE_POSIXDB_READDIR_BLOCK if(p_dir_descriptor->p_dbentries) Mem_Free(p_dir_descriptor->p_dbentries); #endif rc = closedir(p_dir_descriptor->p_dir); if(rc != 0) Return(posix2fsal_error(errno), errno, INDEX_FSAL_closedir); /* fill dir_descriptor with zeros */ memset(p_dir_descriptor, 0, sizeof(posixfsal_dir_t)); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_closedir); }
void Delta_Shutdown( void ) { int i; if( !delta_init ) return; for( i = 0; i < NUM_FIELDS( dt_info ); i++ ) { dt_info[i].numFields = 0; dt_info[i].customEncode = CUSTOM_NONE; dt_info[i].userCallback = NULL; dt_info[i].funcName[0] = '\0'; if( dt_info[i].pFields ) { Mem_Free( dt_info[i].pFields ); dt_info[i].pFields = NULL; } dt_info[i].bInitialized = false; } delta_init = false; }
/* <65aeb> ../engine/net_chan.c:1123 */ void Netchan_FragSend(netchan_t *chan) { fragbufwaiting_t *wait; int i; if (!chan) return; for (i = 0; i < MAX_STREAMS; i++) { // Already something queued up, just leave in waitlist if (chan->fragbufs[i]) { continue; } wait = chan->waitlist[i]; // Nothing to queue? if (!wait) { continue; } chan->waitlist[i] = wait->next; wait->next = NULL; // Copy in to fragbuf chan->fragbufs[i] = wait->fragbufs; chan->fragbufcount[i] = wait->fragbufcount; // Throw away wait list Mem_Free(wait); } }
static void WriteTGA24 (const char *filename, const byte * data, int width, int height, int offset) { int i, size; byte *buffer; qFILE file; size = width * height * 3; /* allocate a buffer and set it up */ buffer = (byte *)Mem_Alloc(size + TGA_HEADER_SIZE); memset(buffer, 0, TGA_HEADER_SIZE); buffer[2] = 2; buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; buffer[15] = height >> 8; buffer[16] = 24; /* create top-down TGA */ buffer[17] = 32; /* swap rgb to bgr */ for (i = 0; i < size; i += 3) { buffer[i + TGA_HEADER_SIZE] = data[i*2 + offset + 2]; /* blue */ buffer[i + TGA_HEADER_SIZE + 1] = data[i*2 + offset + 1]; /* green */ buffer[i + TGA_HEADER_SIZE + 2] = data[i*2 + offset + 0]; /* red */ } /* write it and free the buffer */ if (FS_OpenFile(filename, &file, FILE_WRITE) > 0) Sys_Error("Unable to open %s for writing", filename); FS_Write(buffer, size + TGA_HEADER_SIZE, &file); /* close the file */ FS_CloseFile(&file); Mem_Free(buffer); }
static void SCR_LoadCreditsFont( void ) { byte *buffer; size_t length; int fontWidth; qfont_t *src; // setup creditsfont if( !FS_FileExists( "gfx/creditsfont.fnt", false )) return; // half-life font with variable chars witdh buffer = FS_LoadFile( "gfx/creditsfont.fnt", &length, false ); R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture ); if( buffer && length >= sizeof( qfont_t )) { int i; src = (qfont_t *)buffer; clgame.scrInfo.iCharHeight = src->rowheight; // build rectangles for( i = 0; i < 256; i++ ) { cls.creditsFont.fontRc[i].left = (word)src->fontinfo[i].startoffset % fontWidth; cls.creditsFont.fontRc[i].right = cls.creditsFont.fontRc[i].left + src->fontinfo[i].charwidth; cls.creditsFont.fontRc[i].top = (word)src->fontinfo[i].startoffset / fontWidth; cls.creditsFont.fontRc[i].bottom = cls.creditsFont.fontRc[i].top + src->rowheight; clgame.scrInfo.charWidths[i] = src->fontinfo[i].charwidth; } cls.creditsFont.valid = true; } if( buffer ) Mem_Free( buffer ); }
/** * @brief Bind a keynum to script command * @param[in] keynum Converted from string to keynum * @param[in] binding The script command to bind keynum to * @param[in] space The key space to bind the key for (menu, game or battle) * @sa Key_Bind_f * @sa Key_StringToKeynum * @note If command is empty, this function will only remove the actual key binding instead of setting empty string. */ void Key_SetBinding (int keynum, const char *binding, keyBindSpace_t space) { char **keySpace = NULL; if (keynum == -1 || keynum >= K_KEY_SIZE) return; Com_DPrintf(DEBUG_CLIENT, "Binding for '%s' for space ", binding); switch (space) { case KEYSPACE_UI: keySpace = &menuKeyBindings[keynum]; Com_DPrintf(DEBUG_CLIENT, "menu\n"); break; case KEYSPACE_GAME: keySpace = &keyBindings[keynum]; Com_DPrintf(DEBUG_CLIENT, "game\n"); break; case KEYSPACE_BATTLE: keySpace = &battleKeyBindings[keynum]; Com_DPrintf(DEBUG_CLIENT, "battle\n"); break; default: Com_DPrintf(DEBUG_CLIENT, "failure\n"); return; } /* free old bindings */ if (*keySpace) { Mem_Free(*keySpace); *keySpace = NULL; } /* allocate memory for new binding, but don't set empty commands*/ if (binding) *keySpace = Mem_PoolStrDup(binding, com_genericPool, 0); }
/* ============================== Netchan_CopyNormalFragments ============================== */ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg ) { fragbuf_t *p, *n; if( !chan->incomingready[FRAG_NORMAL_STREAM] ) return false; if( !chan->incomingbufs[FRAG_NORMAL_STREAM] ) { MsgDev( D_ERROR, "Netchan_CopyNormalFragments: Called with no fragments readied\n" ); chan->incomingready[FRAG_NORMAL_STREAM] = false; return false; } p = chan->incomingbufs[FRAG_NORMAL_STREAM]; BF_Init( msg, "NetMessage", net_message_buffer, sizeof( net_message_buffer )); while( p ) { n = p->next; // copy it in BF_WriteBits( msg, BF_GetData( &p->frag_message ), BF_GetNumBitsWritten( &p->frag_message )); Mem_Free( p ); p = n; } chan->incomingbufs[FRAG_NORMAL_STREAM] = NULL; // reset flag chan->incomingready[FRAG_NORMAL_STREAM] = false; return true; }
void VID_StartupGamma( void ) { // Device supports gamma anyway, but cannot do anything with it. fs_offset_t gamma_size; byte *savedGamma; size_t gammaTypeSize = sizeof(glState.stateRamp); // init gamma ramp Q_memset( glState.stateRamp, 0, gammaTypeSize); #if defined(XASH_SDL) glConfig.deviceSupportsGamma = !SDL_GetWindowGammaRamp( host.hWnd, NULL, NULL, NULL); #endif if( !glConfig.deviceSupportsGamma ) { // force to set cvar Cvar_FullSet( "gl_ignorehwgamma", "1", CVAR_GLCONFIG ); MsgDev( D_ERROR, "VID_StartupGamma: hardware gamma unsupported\n"); } if( gl_ignorehwgamma->integer ) { glConfig.deviceSupportsGamma = false; // even if supported! BuildGammaTable( vid_gamma->value, vid_texgamma->value ); MsgDev( D_NOTE, "VID_StartupGamma: software gamma initialized\n" ); return; } // share this extension so engine can grab them GL_SetExtension( GL_HARDWARE_GAMMA_CONTROL, glConfig.deviceSupportsGamma ); savedGamma = FS_LoadFile( "gamma.dat", &gamma_size, false ); if( !savedGamma || gamma_size != (fs_offset_t)gammaTypeSize) { // saved gamma not found or corrupted file FS_WriteFile( "gamma.dat", glState.stateRamp, gammaTypeSize); MsgDev( D_NOTE, "VID_StartupGamma: gamma.dat initialized\n" ); if( savedGamma ) Mem_Free( savedGamma ); } else { GL_BuildGammaTable(); // validate base gamma if( !Q_memcmp( savedGamma, glState.stateRamp, gammaTypeSize)) { // all ok, previous gamma is valid MsgDev( D_NOTE, "VID_StartupGamma: validate screen gamma - ok\n" ); } else if( !Q_memcmp( glState.gammaRamp, glState.stateRamp, gammaTypeSize)) { // screen gamma is equal to render gamma (probably previous instance crashed) // run additional check to make sure for it if( Q_memcmp( savedGamma, glState.stateRamp, gammaTypeSize)) { // yes, current gamma it's totally wrong, restore it from gamma.dat MsgDev( D_NOTE, "VID_StartupGamma: restore original gamma after crash\n" ); Q_memcpy( glState.stateRamp, savedGamma, gammaTypeSize); } else { // oops, savedGamma == glState.stateRamp == glState.gammaRamp // probably r_gamma set as default MsgDev( D_NOTE, "VID_StartupGamma: validate screen gamma - disabled\n" ); } } else if( !Q_memcmp( glState.gammaRamp, savedGamma, gammaTypeSize)) { // saved gamma is equal render gamma, probably gamma.dat wroted after crash // run additional check to make sure it if( Q_memcmp( savedGamma, glState.stateRamp, gammaTypeSize)) { // yes, saved gamma it's totally wrong, get origianl gamma from screen MsgDev( D_NOTE, "VID_StartupGamma: merge gamma.dat after crash\n" ); FS_WriteFile( "gamma.dat", glState.stateRamp, gammaTypeSize); } else { // oops, savedGamma == glState.stateRamp == glState.gammaRamp // probably r_gamma set as default MsgDev( D_NOTE, "VID_StartupGamma: validate screen gamma - disabled\n" ); } } else { // current gamma unset by other application, so we can restore it here MsgDev( D_NOTE, "VID_StartupGamma: restore original gamma after crash\n" ); Q_memcpy( glState.stateRamp, savedGamma, gammaTypeSize); } Mem_Free( savedGamma ); } vid_gamma->modified = true; }
/* <5e43> ../engine/cmd.c:347 */ void Cmd_Exec_f(void) { const char *pszFileName; const char *pszFileExt; char *pszFileData; int nAddLen; FileHandle_t hFile; if (Cmd_Argc() != 2) { Con_Printf("exec <filename> : execute a script file\n"); return; } pszFileName = Cmd_Argv(1); if (!pszFileName || pszFileName[0] == 0) { return; } if (Q_strstr(pszFileName, "\\") || Q_strstr(pszFileName, ":") || Q_strstr(pszFileName, "~") || Q_strstr(pszFileName, "..") || *pszFileName == '/') { Con_Printf("exec %s: invalid path.\n", pszFileName); return; } pszFileExt = COM_FileExtension((char *)pszFileName); if (Q_stricmp(pszFileExt, "cfg") && Q_stricmp(pszFileExt, "rc")) { Con_Printf("exec %s: not a .cfg or .rc file\n", pszFileName); return; } hFile = FS_OpenPathID(pszFileName, "rb", "GAMECONFIG"); if (!hFile) { hFile = FS_OpenPathID(pszFileName, "rb", "GAME"); } if (!hFile) { hFile = FS_Open(pszFileName, "rb"); } if (!hFile) { if (!Q_strstr(pszFileName, "autoexec.cfg") && !Q_strstr(pszFileName, "userconfig.cfg") && !Q_strstr(pszFileName, "hw/opengl.cfg") && !Q_strstr(pszFileName, "joystick.cfg") && !Q_strstr(pszFileName, "game.cfg")) { Con_Printf("couldn't exec %s\n", pszFileName); } return; } nAddLen = FS_Size(hFile); pszFileData = (char *)Mem_Malloc(nAddLen + 1); if (!pszFileData) { Con_Printf("exec: not enough space for %s", pszFileName); FS_Close(hFile); return; } FS_Read(pszFileData, nAddLen, 1, hFile); pszFileData[nAddLen] = 0; FS_Close(hFile); Con_DPrintf("execing %s\n", pszFileName); if (cmd_text.cursize + nAddLen + 2 < cmd_text.maxsize) { Cbuf_InsertTextLines(pszFileData); } else { char *pszDataPtr = pszFileData; while (true) { Cbuf_Execute(); // TODO: This doesn't obey the rule to first execute commands from the file, and then the others in the buffer pszDataPtr = COM_ParseLine(pszDataPtr); if (com_token[0] == 0) { break; } Cbuf_InsertTextLines(com_token); } } Mem_Free(pszFileData); }
/* ================ Sys_ListFiles ================ */ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list ) { struct dirent* d; DIR* fdir; bool dironly = false; char search[MAX_OSPATH]; struct stat st; bool debug; list.Clear(); debug = cvarSystem->GetCVarBool( "fs_debug" ); // DG: we use fnmatch for shell-style pattern matching // so the pattern should at least contain "*" to match everything, // the extension will be added behind that (if !dironly) idStr pattern( "*" ); // passing a slash as extension will find directories if( extension[0] == '/' && extension[1] == 0 ) { dironly = true; } else { // so we have *<extension>, the same as in the windows code basically pattern += extension; } // DG end // NOTE: case sensitivity of directory path can screw us up here if( ( fdir = opendir( directory ) ) == NULL ) { if( debug ) { common->Printf( "Sys_ListFiles: opendir %s failed\n", directory ); } return -1; } // DG: use readdir_r instead of readdir for thread safety // the following lines are from the readdir_r manpage.. fscking ugly. int nameMax = pathconf( directory, _PC_NAME_MAX ); if( nameMax == -1 ) nameMax = 255; int direntLen = offsetof( struct dirent, d_name ) + nameMax + 1; struct dirent* entry = ( struct dirent* )Mem_Alloc( direntLen, TAG_CRAP ); if( entry == NULL ) { common->Warning( "Sys_ListFiles: Mem_Alloc for entry failed!" ); closedir( fdir ); return 0; } while( readdir_r( fdir, entry, &d ) == 0 && d != NULL ) { // DG end idStr::snPrintf( search, sizeof( search ), "%s/%s", directory, d->d_name ); if( stat( search, &st ) == -1 ) continue; if( !dironly ) { // DG: the original code didn't work because d3 bfg abuses the extension // to match whole filenames and patterns in the savegame-code, not just file extensions... // so just use fnmatch() which supports matching shell wildcard patterns ("*.foo" etc) // if we should ever need case insensitivity, use FNM_CASEFOLD as third flag if( fnmatch( pattern.c_str(), d->d_name, 0 ) != 0 ) continue; // DG end } if( ( dironly && !( st.st_mode & S_IFDIR ) ) || ( !dironly && ( st.st_mode & S_IFDIR ) ) ) continue; list.Append( d->d_name ); } closedir( fdir ); Mem_Free( entry ); if( debug ) { common->Printf( "Sys_ListFiles: %d entries in %s\n", list.Num(), directory ); } return list.Num(); }
/** * * nfs_read_core_conf: read the configuration ite; for the worker theads. * * Reads the configuration ite; for the worker theads. * * @param in_config [IN] configuration file handle * @param pparam [OUT] read parameters * * @return 0 if ok, -1 if failed, 1 is stanza is not there. * */ int nfs_read_core_conf(config_file_t in_config, nfs_core_parameter_t * pparam) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; /* Is the config tree initialized ? */ if(in_config == NULL || pparam == NULL) return CACHE_INODE_INVALID_ARGUMENT; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_LABEL_NFS_CORE)) == NULL) { LogDebug(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_NFS_CORE); return 1; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogDebug(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_NFS_CORE); return 1; } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogCrit(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_NFS_CORE); return CACHE_INODE_INVALID_ARGUMENT; } if(!strcasecmp(key_name, "Nb_Worker")) { pparam->nb_worker = atoi(key_value); } else if(!strcasecmp(key_name, "Nb_Call_Before_Queue_Avg")) { pparam->nb_call_before_queue_avg = atoi(key_value); } else if(!strcasecmp(key_name, "Nb_MaxConcurrentGC")) { pparam->nb_max_concurrent_gc = atoi(key_value); } else if(!strcasecmp(key_name, "DupReq_Expiration")) { pparam->expiration_dupreq = atoi(key_value); } else if(!strcasecmp(key_name, "Drop_IO_Errors")) { pparam->drop_io_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Drop_Inval_Errors")) { pparam->drop_inval_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Drop_Delay_Errors")) { pparam->drop_delay_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "NFS_Port")) { pparam->port[P_NFS] = (unsigned short)atoi(key_value); } else if(!strcasecmp(key_name, "MNT_Port")) { pparam->port[P_MNT] = (unsigned short)atoi(key_value); } else if(!strcasecmp(key_name, "NLM_Port")) { #ifdef _USE_NLM pparam->port[P_NLM] = (unsigned short)atoi(key_value); #endif } else if(!strcasecmp(key_name, "Rquota_Port")) { #ifdef _USE_QUOTA pparam->port[P_RQUOTA] = (unsigned short)atoi(key_value); #endif } else if(!strcasecmp(key_name, "NFS_Program")) { pparam->program[P_NFS] = atoi(key_value); } else if(!strcasecmp(key_name, "MNT_Program")) { pparam->program[P_MNT] = atoi(key_value); } else if(!strcasecmp(key_name, "NLM_Program")) { #ifdef _USE_NLM pparam->program[P_NLM] = atoi(key_value); #endif } else if(!strcasecmp(key_name, "Rquota_Program")) { #ifdef _USE_QUOTA pparam->program[P_RQUOTA] = atoi(key_value); #endif } else if(!strcasecmp(key_name, "NFS_Protocols")) { # define MAX_NFSPROTO 10 /* large enough !!! */ # define MAX_NFSPROTO_LEN 256 /* so is it !!! */ char *nfsvers_list[MAX_NFSPROTO]; int idx, count; /* reset nfs versions flags (clean defaults) */ pparam->core_options &= ~(CORE_OPTION_ALL_VERS); /* allocate nfs vers strings */ for(idx = 0; idx < MAX_NFSPROTO; idx++) nfsvers_list[idx] = (char *)Mem_Alloc(MAX_NFSPROTO_LEN); /* * Search for coma-separated list of nfsprotos */ count = nfs_ParseConfLine(nfsvers_list, MAX_NFSPROTO, key_value, find_comma, find_endLine); if(count < 0) { LogCrit(COMPONENT_CONFIG, "NFS_Protocols list too long (>%d)", MAX_NFSPROTO); /* free sec strings */ for(idx = 0; idx < MAX_NFSPROTO; idx++) Mem_Free((caddr_t) nfsvers_list[idx]); return -1; } /* add each Nfs protocol flag to the option field. */ for(idx = 0; idx < count; idx++) { if(!strcmp(nfsvers_list[idx], "4")) { pparam->core_options |= CORE_OPTION_NFSV4; } /* only NFSv4 is supported for the FSAL_PROXY */ #if ! defined( _USE_PROXY ) || defined ( _HANDLE_MAPPING ) else if(!strcmp(nfsvers_list[idx], "2")) { pparam->core_options |= CORE_OPTION_NFSV2; } else if(!strcmp(nfsvers_list[idx], "3")) { pparam->core_options |= CORE_OPTION_NFSV3; } #endif /* _USE_PROXY */ else { LogCrit(COMPONENT_CONFIG, "Invalid NFS Protocol \"%s\". Values can be: 2, 3, 4.", nfsvers_list[idx]); return -1; } } /* free sec strings */ for(idx = 0; idx < MAX_NFSPROTO; idx++) Mem_Free((caddr_t) nfsvers_list[idx]); /* check that at least one nfs protocol has been specified */ if((pparam->core_options & (CORE_OPTION_ALL_VERS)) == 0) { LogCrit(COMPONENT_CONFIG, "Empty NFS_Protocols list"); return -1; } } else if(!strcasecmp(key_name, "Bind_Addr")) { int rc; memset(&pparam->bind_addr.sin_addr, 0, sizeof(pparam->bind_addr.sin_addr)); rc = inet_pton(AF_INET, key_value, &pparam->bind_addr.sin_addr); if(rc <= 0) { /* Revert to INADDR_ANY in case of any error */ pparam->bind_addr.sin_addr.s_addr = INADDR_ANY; /* All the interfaces on the machine are used */ } } else if(!strcasecmp(key_name, "Core_Dump_Size")) { pparam->core_dump_size = atol(key_value); } else if(!strcasecmp(key_name, "Nb_Max_Fd")) { pparam->nb_max_fd = atoi(key_value); } else if(!strcasecmp(key_name, "Stats_File_Path")) { strncpy(pparam->stats_file_path, key_value, MAXPATHLEN); } else if(!strcasecmp(key_name, "Stats_Update_Delay")) { pparam->stats_update_delay = atoi(key_value); } else if(!strcasecmp(key_name, "Long_Processing_Threshold")) { pparam->long_processing_threshold = atoi(key_value); } else if(!strcasecmp( key_name, "TCP_Fridge_Expiration_Delay" ) ) { pparam->tcp_fridge_expiration_delay = atoi(key_value); } else if(!strcasecmp(key_name, "Dump_Stats_Per_Client")) { pparam->dump_stats_per_client = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Stats_Per_Client_Directory")) { strncpy(pparam->stats_per_client_directory, key_value, MAXPATHLEN); } else if(!strcasecmp(key_name, "FSAL_Shared_Library")) { strncpy(pparam->fsal_shared_library, key_value, MAXPATHLEN); } else { LogCrit(COMPONENT_CONFIG, "Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_NFS_CORE); return -1; } } return 0; } /* nfs_read_core_conf */
/* ================= R_StaticFree ================= */ void R_StaticFree( void *data ) { tr.pc.c_free++; Mem_Free( data ); }
/* ==================== ModPlug_FetchSound ==================== */ static const snd_buffer_t* ModPlug_FetchSound (void *sfxfetcher, void **chfetcherpointer, unsigned int *start, unsigned int nbsampleframes) { modplug_stream_perchannel_t* per_ch = (modplug_stream_perchannel_t *)*chfetcherpointer; modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfxfetcher; snd_buffer_t* sb; int newlength, done, ret; unsigned int real_start; unsigned int factor; // If there's no fetcher structure attached to the channel yet if (per_ch == NULL) { size_t buff_len, memsize; snd_format_t sb_format; sb_format.speed = snd_renderbuffer->format.speed; sb_format.width = per_sfx->format.width; sb_format.channels = per_sfx->format.channels; buff_len = STREAM_BUFFER_SIZE(&sb_format); memsize = sizeof (*per_ch) - sizeof (per_ch->sb.samples) + buff_len; per_ch = (modplug_stream_perchannel_t *)Mem_Alloc (snd_mempool, memsize); // Open it with the modplugFile API per_ch->mf = qModPlug_Load(per_sfx->file, per_sfx->filesize); if (!per_ch->mf) { Con_Printf("error while reading ModPlug stream \"%s\"\n", per_sfx->name); Mem_Free (per_ch); return NULL; } #ifndef SND_MODPLUG_STATIC if(qModPlug_SetMasterVolume) #endif qModPlug_SetMasterVolume(per_ch->mf, 512); // max volume, DP scales down! per_ch->bs = 0; per_ch->sb_offset = 0; per_ch->sb.format = sb_format; per_ch->sb.nbframes = 0; per_ch->sb.maxframes = buff_len / (per_ch->sb.format.channels * per_ch->sb.format.width); *chfetcherpointer = per_ch; } real_start = *start; sb = &per_ch->sb; factor = per_sfx->format.width * per_sfx->format.channels; // If the stream buffer can't contain that much samples anyway if (nbsampleframes > sb->maxframes) { Con_Printf ("ModPlug_FetchSound: stream buffer too small (%u sample frames required)\n", nbsampleframes); return NULL; } // If the data we need has already been decompressed in the sfxbuffer, just return it if (per_ch->sb_offset <= real_start && per_ch->sb_offset + sb->nbframes >= real_start + nbsampleframes) { *start = per_ch->sb_offset; return sb; } newlength = (int)(per_ch->sb_offset + sb->nbframes) - real_start; // If we need to skip some data before decompressing the rest, or if the stream has looped if (newlength < 0 || per_ch->sb_offset > real_start) { unsigned int time_start; unsigned int modplug_start; /* MODs loop on their own, so any position is valid! if (real_start > (unsigned int)per_sfx->total_length) { Con_Printf ("ModPlug_FetchSound: asked for a start position after the end of the sfx! (%u > %u)\n", real_start, per_sfx->total_length); return NULL; } */ // We work with 200ms (1/5 sec) steps to avoid rounding errors time_start = real_start * 5 / snd_renderbuffer->format.speed; modplug_start = time_start * (1000 / 5); Con_DPrintf("warning: mod file needed to seek (to %d)\n", modplug_start); qModPlug_Seek(per_ch->mf, modplug_start); sb->nbframes = 0; real_start = (unsigned int) ((float)modplug_start / 1000 * snd_renderbuffer->format.speed); if (*start - real_start + nbsampleframes > sb->maxframes) { Con_Printf ("ModPlug_FetchSound: stream buffer too small after seek (%u sample frames required)\n", *start - real_start + nbsampleframes); per_ch->sb_offset = real_start; return NULL; } } // Else, move forward the samples we need to keep in the sound buffer else { memmove (sb->samples, sb->samples + (real_start - per_ch->sb_offset) * factor, newlength * factor); sb->nbframes = newlength; } per_ch->sb_offset = real_start; // We add more than one frame of sound to the buffer: // 1- to ensure we won't lose many samples during the resampling process // 2- to reduce calls to ModPlug_FetchSound to regulate workload newlength = (int)(per_sfx->format.speed*STREAM_BUFFER_FILL); if ((size_t) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes > sb->maxframes) { Con_Printf ("ModPlug_FetchSound: stream buffer overflow (%u + %u = %u sample frames / %u)\n", (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed), sb->nbframes, (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes, sb->maxframes); return NULL; } newlength *= factor; // convert from sample frames to bytes if(newlength > (int)sizeof(resampling_buffer)) newlength = sizeof(resampling_buffer); // Decompress in the resampling_buffer done = 0; while ((ret = qModPlug_Read (per_ch->mf, (char *)&resampling_buffer[done], (int)(newlength - done))) > 0) done += ret; if(done < newlength) { // Argh. We didn't get as many samples as we wanted. Probably // libmodplug forgot what mLoopCount==-1 means... basically, this means // we can't loop like this. Try to let DP fix it later... per_sfx->sfx->total_length = (real_start + ((size_t)done / (size_t)factor)); per_sfx->sfx->loopstart = 0; if(newlength != done) Con_DPrintf("ModPlug_Fetch: wanted: %d, got: %d\n", newlength, done); } Snd_AppendToSndBuffer (sb, resampling_buffer, (size_t)done / (size_t)factor, &per_sfx->format); *start = per_ch->sb_offset; return sb; }
/* ==================== ModPlug_LoadmodplugFile Load an modplug file into memory ==================== */ qboolean ModPlug_LoadModPlugFile (const char *filename, sfx_t *sfx) { unsigned char *data; fs_offset_t filesize; ModPlugFile *mf; modplug_stream_persfx_t* per_sfx; ModPlug_Settings s; if (!modplug_dll) return false; // Already loaded? if (sfx->fetcher != NULL) return true; // Load the file data = FS_LoadFile (filename, snd_mempool, false, &filesize); if (data == NULL) return false; if (developer_loading.integer >= 2) Con_Printf ("Loading ModPlug file \"%s\"\n", filename); qModPlug_GetSettings(&s); s.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION | MODPLUG_ENABLE_REVERB; s.mChannels = 2; s.mBits = 16; s.mFrequency = 44100; s.mResamplingMode = MODPLUG_RESAMPLE_SPLINE; s.mLoopCount = -1; qModPlug_SetSettings(&s); // Open it with the modplugFile API if (!(mf = qModPlug_Load (data, filesize))) { Con_Printf ("error while opening ModPlug file \"%s\"\n", filename); Mem_Free(data); return false; } #ifndef SND_MODPLUG_STATIC if(qModPlug_SetMasterVolume) #endif qModPlug_SetMasterVolume(mf, 512); // max volume, DP scales down! if (developer_loading.integer >= 2) Con_Printf ("\"%s\" will be streamed\n", filename); per_sfx = (modplug_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx)); strlcpy(per_sfx->name, sfx->name, sizeof(per_sfx->name)); sfx->memsize += sizeof (*per_sfx); per_sfx->file = data; per_sfx->filesize = filesize; sfx->memsize += filesize; per_sfx->format.speed = 44100; // modplug always works at that rate per_sfx->format.width = 2; // We always work with 16 bits samples per_sfx->format.channels = 2; // stereo rulez ;) (MAYBE default to mono because Amiga MODs sound better then?) per_sfx->sfx = sfx; sfx->fetcher_data = per_sfx; sfx->fetcher = &modplug_fetcher; sfx->flags |= SFXFLAG_STREAMED; sfx->total_length = 2147384647; // they always loop sfx->loopstart = sfx->total_length; // modplug does it return true; }
static void SCR_CaptureVideo_Ogg_EndVideo(void) { LOAD_FORMATSPECIFIC_OGG(); ogg_page pg; ogg_packet pt; if(format->yuvi >= 0) { // send the previous (and last) frame while(format->lastnum-- > 0) { qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]); while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt)) qogg_stream_packetin(&format->to, &pt); SCR_CaptureVideo_Ogg_Interleave(); } } if(cls.capturevideo.soundrate) { qvorbis_analysis_wrote(&format->vd, 0); while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1) { qvorbis_analysis(&format->vb, NULL); qvorbis_bitrate_addblock(&format->vb); while(qvorbis_bitrate_flushpacket(&format->vd, &pt)) qogg_stream_packetin(&format->vo, &pt); SCR_CaptureVideo_Ogg_Interleave(); } } SCR_CaptureVideo_Ogg_FlushInterleaving(); while(qogg_stream_pageout(&format->to, &pg) > 0) { FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); } if(cls.capturevideo.soundrate) { while(qogg_stream_pageout(&format->vo, &pg) > 0) { FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); } } while (1) { int result = qogg_stream_flush (&format->to, &pg); if (result < 0) fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); } if(cls.capturevideo.soundrate) { while (1) { int result = qogg_stream_flush (&format->vo, &pg); if (result < 0) fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); } qogg_stream_clear(&format->vo); qvorbis_block_clear(&format->vb); qvorbis_dsp_clear(&format->vd); } qogg_stream_clear(&format->to); qtheora_clear(&format->ts); qvorbis_info_clear(&format->vi); Mem_Free(format->yuv[0].y); Mem_Free(format->yuv[0].u); Mem_Free(format->yuv[0].v); Mem_Free(format->yuv[1].y); Mem_Free(format->yuv[1].u); Mem_Free(format->yuv[1].v); Mem_Free(format); FS_Close(cls.capturevideo.videofile); cls.capturevideo.videofile = NULL; }
/** * @brief Change the server to a new map, taking all connected clients along with it. * @note the full syntax is: @code map [day|night] [+]<map> [<assembly>] @endcode * @sa SV_AssembleMap * @sa CM_LoadMap * @sa Com_SetServerState */ void SV_Map (qboolean day, const char *levelstring, const char *assembly) { int i; unsigned checksum = 0; char * map = SV_GetConfigString(CS_TILES); char * pos = SV_GetConfigString(CS_POSITIONS); mapInfo_t *randomMap = NULL; client_t *cl; /* any partially connected client will be restarted */ Com_SetServerState(ss_restart); /* the game is just starting */ SV_InitGame(); if (!svs.initialized) { Com_Printf("Could not spawn the server\n"); return; } assert(levelstring[0] != '\0'); Com_DPrintf(DEBUG_SERVER, "SpawnServer: %s\n", levelstring); /* save name for levels that don't set message */ SV_SetConfigString(CS_NAME, levelstring); SV_SetConfigString(CS_LIGHTMAP, day); Q_strncpyz(sv->name, levelstring, sizeof(sv->name)); /* set serverinfo variable */ sv_mapname = Cvar_FullSet("sv_mapname", sv->name, CVAR_SERVERINFO | CVAR_NOSET); /* notify the client in case of a listening server */ SCR_BeginLoadingPlaque(); if (assembly) Q_strncpyz(sv->assembly, assembly, sizeof(sv->assembly)); else sv->assembly[0] = '\0'; /* leave slots at start for clients only */ cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { /* needs to reconnect */ if (cl->state >= cs_spawning) SV_SetClientState(cl, cs_connected); } /* assemble and load the map */ if (levelstring[0] == '+') { randomMap = SV_AssembleMap(levelstring + 1, assembly, map, pos, 0); if (!randomMap) { Com_Printf("Could not load assembly for map '%s'\n", levelstring); return; } } else { SV_SetConfigString(CS_TILES, levelstring); SV_SetConfigString(CS_POSITIONS, assembly ? assembly : ""); } CM_LoadMap(map, day, pos, &sv->mapData, &sv->mapTiles); Com_Printf("checksum for the map '%s': %u\n", levelstring, sv->mapData.mapChecksum); SV_SetConfigString(CS_MAPCHECKSUM, sv->mapData.mapChecksum); checksum = Com_GetScriptChecksum(); Com_Printf("ufo script checksum %u\n", checksum); SV_SetConfigString(CS_UFOCHECKSUM, checksum); SV_SetConfigString(CS_OBJECTAMOUNT, csi.numODs); SV_SetConfigString(CS_VERSION, UFO_VERSION); SV_SetConfigString(CS_MAPTITLE, SV_GetMapTitle(randomMap, levelstring)); if (Q_strstart(SV_GetConfigString(CS_MAPTITLE), "b/")) { /* For base attack, CS_MAPTITLE contains too many chars */ SV_SetConfigString(CS_MAPTITLE, "Base attack"); SV_SetConfigString(CS_NAME, ".baseattack"); } /* clear random-map assembly data */ Mem_Free(randomMap); randomMap = NULL; /* clear physics interaction links */ SV_ClearWorld(); /* fix this! */ for (i = 1; i <= sv->mapData.numInline; i++) sv->models[i] = CM_InlineModel(&sv->mapTiles, va("*%i", i)); /* precache and static commands can be issued during map initialization */ Com_SetServerState(ss_loading); TH_MutexLock(svs.serverMutex); /* load and spawn all other entities */ svs.ge->SpawnEntities(sv->name, SV_GetConfigStringInteger(CS_LIGHTMAP), sv->mapData.mapEntityString); TH_MutexUnlock(svs.serverMutex); /* all precaches are complete */ Com_SetServerState(ss_game); Com_Printf("-------------------------------------\n"); Cbuf_CopyToDefer(); }
void FreeTree (tree_t *tree) { FreeTreePortals_r(tree->headnode); FreeTree_r(tree->headnode); Mem_Free(tree); }
/* Free a struct cidr_addr */ void cidr_free(CIDR *tofree) { Mem_Free(tofree); }
void MD2SkinNum (const byte* buf, const char* fileName, int bufSize, void* userData) { byte* copy = Mem_Dup(byte, buf, bufSize); dMD2Model_t* md2 = (dMD2Model_t*)copy; MD2HeaderCheck(md2, fileName, bufSize); const uint32_t numSkins = LittleLong(md2->num_skins); const uint32_t ofsST = LittleLong(md2->ofs_st); const uint32_t ofsTris = LittleLong(md2->ofs_tris); const uint32_t ofsFrames = LittleLong(md2->ofs_frames); const uint32_t ofsGLCmds = LittleLong(md2->ofs_glcmds); const uint32_t ofsEnd = LittleLong(md2->ofs_end); const uint32_t ofsSkins = LittleLong(md2->ofs_skins); uint32_t moveOffset = ofsEnd; #define CHECKMAX(val) if ((val) > ofsSkins && (val) < moveOffset) moveOffset = (val); CHECKMAX(ofsST); CHECKMAX(ofsTris); CHECKMAX(ofsFrames); CHECKMAX(ofsGLCmds); CHECKMAX(ofsSkins); #undef CHECKMAX Com_Printf(" \\ - skins %i\n", numSkins); int newSkins = 0; printf(" \\ - new skin number: "); fflush(stdout); scanf("%i", &newSkins); if (newSkins <= 0) { Com_Printf("A model must have a skin\n"); Mem_Free(copy); return; } if (newSkins > MD2_MAX_SKINS) { Com_Printf("Only %i skins are allowed\n", MD2_MAX_SKINS); Mem_Free(copy); return; } if (newSkins == numSkins) { Mem_Free(copy); return; } const int32_t deltaSkins = newSkins - numSkins; const int32_t offsetDelta = deltaSkins * MD2_MAX_SKINNAME; if (ofsST > ofsSkins) md2->ofs_st = LittleLong(ofsST + offsetDelta); if (ofsTris > ofsSkins) md2->ofs_tris = LittleLong(ofsTris + offsetDelta); if (ofsFrames > ofsSkins) md2->ofs_frames = LittleLong(ofsFrames + offsetDelta); if (ofsGLCmds > ofsSkins) md2->ofs_glcmds = LittleLong(ofsGLCmds + offsetDelta); md2->ofs_end = LittleLong(ofsEnd + offsetDelta); md2->num_skins = LittleLong(newSkins); Com_Printf("change to %i skins\n", newSkins); if (deltaSkins > 0) { copy = (byte*)Mem_ReAlloc(copy, md2->ofs_end); md2 = (dMD2Model_t*)copy; } const int n = ofsEnd - moveOffset; byte* from = copy + moveOffset; byte* to = from + offsetDelta; memmove(to, from, n); if (deltaSkins > 0) { char* md2Path = (char*) copy + LittleLong(md2->ofs_skins); for (int i = numSkins; i < numSkins + deltaSkins; i++) { char* name = md2Path + i * MD2_MAX_SKINNAME; memset(name, 0, MD2_MAX_SKINNAME); strcpy(name, ".none"); Com_Printf(" \\ - skin %i: %s\n", i + 1, name); printf(" \\ - new skin: "); fflush(stdout); scanf(va("%%%is", MD2_MAX_SKINNAME), name); } } ScopedFile md2ModelFile; FS_OpenFile(fileName, &md2ModelFile, FILE_WRITE); if (!md2ModelFile) { Com_Printf("Error writing md2 file %s\n", fileName); Mem_Free(copy); return; } FS_Write(copy, md2->ofs_end, &md2ModelFile); Mem_Free(copy); }