Beispiel #1
0
BOOL C4UpdatePackage::Optimize(C4Group *pGroup, const char *strTarget) {
    // Open target group
    C4GroupEx TargetGrp;
    if (!TargetGrp.Open(strTarget)) return FALSE;

    // Both groups must be packed
    if (!pGroup->IsPacked() || !TargetGrp.IsPacked()) {
        TargetGrp.Close(FALSE);
        return FALSE;
    }

    // update children
    char ItemFileName[_MAX_PATH];
    pGroup->ResetSearch();
    while (pGroup->FindNextEntry("*", ItemFileName))
        if (!SEqual(ItemFileName, C4CFN_UpdateCore) &&
                !SEqual(ItemFileName, C4CFN_UpdateEntries))
            Optimize(pGroup, &TargetGrp, ItemFileName);

    // set header
    if (TargetGrp.HeadIdentical(*pGroup, true)) TargetGrp.SetHead(*pGroup);

    // save
    TargetGrp.Close(FALSE);

    // okay
    return TRUE;
}
Beispiel #2
0
void C4Application::OnCommand(const char *szCmd) {
  // Find parameters
  const char *szPar = strchr(szCmd, ' ');
  while (szPar && *szPar == ' ') szPar++;

  if (SEqual(szCmd, "/quit")) {
    Quit();
    return;
  }

  switch (AppState) {
    case C4AS_Startup:

      // Open a new game
      if (SEqual2(szCmd, "/open ")) {
        // Try to start the game with given parameters
        AppState = C4AS_Game;
        Game.ParseCommandLine(szPar);
        UseStartupDialog = true;
        if (!Game.Init()) AppState = C4AS_Startup;
      }

      break;

    case C4AS_Game:

      // Clear running game
      if (SEqual(szCmd, "/close")) {
        Game.Clear();
        Game.Default();
        AppState = C4AS_PreInit;
        UseStartupDialog = true;
        return;
      }

      // Lobby commands
      if (Game.Network.isLobbyActive()) {
        if (SEqual2(szCmd, "/start")) {
          // timeout given?
          int32_t iTimeout = Config.Lobby.CountdownTime;
          if (!Game.Network.isHost())
            Log(LoadResStr("IDS_MSG_CMD_HOSTONLY"));
          else if (szPar && (!sscanf(szPar, "%d", &iTimeout) || iTimeout < 0))
            Log(LoadResStr("IDS_MSG_CMD_START_USAGE"));
          else
            // start new countdown (aborts previous if necessary)
            Game.Network.StartLobbyCountdown(iTimeout);
          break;
        }
      }

      // Normal commands
      Game.MessageInput.ProcessInput(szCmd);
      break;
  }
}
Beispiel #3
0
bool TexColSingle(const char *mattex, uint8_t& col)
{
	if (SEqual(mattex, DrawFn_Transparent_Name)) { col = 0; return true; }
	if (SEqual(mattex, DrawFn_Sky_Name)) { col = C4M_MaxTexIndex; return true; }

	col = ::MapScript.pTexMap->GetIndexMatTex(mattex);
	if (col == 0) return false;

	return true;
}
bool C4StartupNetListEntry::IsSameHost(const C4Network2Reference *pRef2)
{
	// not if ref has not been retrieved yet
	if (!pRef) return false;
	C4Client *pHost1 = pRef->Parameters.Clients.getHost();
	C4Client *pHost2 = pRef2->Parameters.Clients.getHost();
	if (!pHost1 || !pHost2) return false;
	// check
	return SEqual(pHost1->getCUID(), pHost2->getCUID()) && SEqual(pHost1->getName(), pHost2->getName());
}
Beispiel #5
0
bool C4UpdatePackage::DoUpdate(C4Group *pGrpFrom, C4GroupEx *pGrpTo, const char *strFileName)
{
	// group file?
	C4Group ItemGroupFrom;
	if (ItemGroupFrom.OpenAsChild(pGrpFrom, strFileName))
	{
		// try to open target group
		C4GroupEx ItemGroupTo;
		char strTempGroup[_MAX_PATH+1]; strTempGroup[0] = 0;
		if (!ItemGroupTo.OpenAsChild(pGrpTo, strFileName, false, true))
			return false;
		// update children
		char ItemFileName[_MAX_PATH];
		ItemGroupFrom.ResetSearch();
		while (ItemGroupFrom.FindNextEntry("*", ItemFileName))
			if (!SEqual(ItemFileName, C4CFN_UpdateCore) && !SEqual(ItemFileName, C4CFN_UpdateEntries))
				DoUpdate(&ItemGroupFrom, &ItemGroupTo, ItemFileName);
		if (GrpUpdate)
		{
			DoGrpUpdate(&ItemGroupFrom, &ItemGroupTo);
			// write group (do not change any headers set by DoGrpUpdate!)
			ItemGroupTo.Close(false);
			// set core (C4Group::Save overwrites it)
			pGrpTo->SaveEntryCore(*pGrpFrom, strFileName);
			pGrpTo->SetSavedEntryCore(strFileName);
			// flag as no-resort
			pGrpTo->SetNoSort(strFileName);
		}
		else
		{
			// write group
			ItemGroupTo.Close(true);
			// temporary group?
			if (strTempGroup[0])
				if (!pGrpTo->Move(strTempGroup, strFileName))
					return false;
		}
	}
	else
	{
#ifdef _WIN32
		OutputDebugString(FormatString("updating %s\\%s\n", pGrpTo->GetFullName().getData(), strFileName).GetWideChar());
#elif defined(_DEBUG)
		printf("updating %s\\%s\n", pGrpTo->GetFullName().getData(), strFileName);
#endif
		if (!C4Group_CopyEntry(pGrpFrom, pGrpTo, strFileName))
			return false;
		// set core
		pGrpTo->SaveEntryCore(*pGrpFrom, strFileName);
		pGrpTo->SetSavedEntryCore(strFileName);
	}
	// ok
	return true;
}
Beispiel #6
0
private func Activity() {
  var pBait;
  // Ein Köder in der Nähe?
  if (pBait=FindObject(0,-1000,-1250,2000,1500, OCF_InLiquid(), "Bait" ) )
    // Schwarze Fische sind nicht wählerisch
    SetCommand(this(),"Follow",pBait);

  // Schwimmverhalten
  if (!GBackLiquid (0, -8)) return (SetComDir (COMD_Down ()));
  if (Random(2)) return(1);
  if (SEqual(GetAction(),"Walk")) WalkDir();
  if (Not( SEqual(GetAction(),"Swim") )) return(1);
  if (Random(2)) return(TurnRight(),SetComDir(COMD_Right()));
  return(TurnLeft(),SetComDir(COMD_Left()));
}
Beispiel #7
0
char *GetResStr(const char *id, const char *strTable)
{
	const char *pos;
	// Default
	sprintf(strResult, "[Undefined:%s]", id);
	// Compose identifier with operator
	char idExt[256 + 1 + 1]; SCopy(id, idExt, 256); SAppendChar('=', idExt);
	// String table present and id not empty
	if (strTable && id && id[0])
		// Search for identifier with operator
		if ((pos = SSearch(strTable, idExt)))
			// Get string until end of line
			SCopyUntil(pos, strResult, "\r\n", ResStrMaxLen);
	// Compile line feeds ("\n" -> 0D0A)
	pos = strResult;
	while ((pos = SSearch(pos, "\\n")))
		{ ((char*)pos)[-2] = 0x0D; ((char*)pos)[-1] = 0x0A; }
#ifdef _DEBUG
#ifdef _MSC_VER
	if (SEqual2(strResult, "[Undefined:"))
		if (!SEqual(id, "IDS_LANG_CHARSET"))
			{
			/* __asm int 3 */
			}
#endif
#endif
	// Return string
	return strResult;
}
Beispiel #8
0
C4Team *C4TeamList::GetTeamByName(const char *szName) const
{
	assert(szName);
	C4Team **ppCheck=ppList; int32_t iCnt=iTeamCount;
	for (; iCnt--; ++ppCheck) if (SEqual((*ppCheck)->GetName(), szName)) return *ppCheck;
	return NULL;
}
bool C4Network2Res::OptimizeStandalone(bool fSilent)
{
	CStdLock FileLock(&FileCSec);
	// for now: player files only
	if (Core.getType() == NRT_Player)
	{
		// log - this may take a few seconds
		if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPREPARING"), GetFilename(szFile));
		// copy to temp file, if needed
		if (!fTempFile && SEqual(szFile, szStandalone))
		{
			char szNewStandalone[_MAX_PATH + 1];
			if (!pParent->FindTempResFileName(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not find free name for temporary file!"); return false; }
			if (!C4Group_CopyItem(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not copy to temporary file!"); return false; } /* TODO: Test failure */
			SCopy(szNewStandalone, szStandalone, sizeof(szStandalone) - 1);
		}
		// open as group
		C4Group Grp;
		if (!Grp.Open(szStandalone))
			{ if (!fSilent) Log("OptimizeStandalone: could not open player file!"); return false; }
		// remove bigicon, if the file size is too large
		size_t iBigIconSize=0;
		if (Grp.FindEntry(C4CFN_BigIcon, NULL, &iBigIconSize))
			if (iBigIconSize > C4NetResMaxBigicon*1024)
				Grp.Delete(C4CFN_BigIcon);
		Grp.Close();
	}
	return true;
}
Beispiel #10
0
C4Network2Client *C4Network2ClientList::GetClient(const char *szName) const
{
	for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->pNext)
		if (SEqual(pClient->getName(), szName))
			return pClient;
	return NULL;
}
C4Network2IRCUser *C4Network2IRCChannel::getUser(const char *szName) const
	{
	for(C4Network2IRCUser *pUser = pUsers; pUser; pUser = pUser->Next)
		if(SEqual(pUser->getName(), szName))
			return pUser;
	return NULL;
	}
Beispiel #12
0
int32_t C4ValueMapNames::GetItemNr(const char *strName) const
{
	for (int32_t i = 0; i < iSize; i++)
		if (SEqual(pNames[i], strName))
			return i;
	return -1;
}
Beispiel #13
0
bool C4MaterialMap::SortEnumeration(int32_t iMat, const char *szMatName)
{

	// Not enough materials loaded
	if (iMat>=Num) return false;

	// Find requested mat
	int32_t cmat;
	for (cmat=iMat; cmat<Num; cmat++)
		if (SEqual(szMatName,Map[cmat].Name))
			break;
	// Not found
	if (cmat>=Num) return false;

	// already the same?
	if (cmat == iMat) return true;

	// Move requested mat to indexed position
	C4Material mswap;
	mswap = Map[iMat];
	Map[iMat] = Map[cmat];
	Map[cmat] = mswap;

	return true;
}
void C4MusicSystem::LoadMoreMusic()
{
	StdStrBuf MoreMusicFile;
	// load MoreMusic.txt
	if (!MoreMusicFile.LoadFromFile(Config.AtUserDataPath(C4CFN_MoreMusic))) return;
	// read contents
	char *pPos = MoreMusicFile.getMData();
	while (pPos && *pPos)
	{
		// get line
		char szLine[1024 + 1];
		SCopyUntil(pPos, szLine, '\n', 1024);
		pPos = strchr(pPos, '\n'); if (pPos) pPos++;
		// remove leading whitespace
		char *pLine = szLine;
		while (*pLine == ' ' || *pLine == '\t' || *pLine == '\r') pLine++;
		// and whitespace at end
		char *p = pLine + strlen(pLine) - 1;
		while (*p == ' ' || *p == '\t' || *p == '\r') { *p = 0; --p; }
		// comment?
		if (*pLine == '#')
		{
			// might be a "directive"
			if (SEqual(pLine, "#clear"))
				ClearSongs();
			continue;
		}
		// try to load file(s)
		LoadDir(pLine);
	}
}
C4Player* C4PlayerList::GetByName(const char *szName, int iExcluding) const
{
	for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next)
		if (SEqual(pPlr->GetName(),szName))
			if (pPlr->Number!=iExcluding)
				return pPlr;
	return NULL;
}
Beispiel #16
0
C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
{
	if (!Name) return nullptr;
	C4AulFunc * Func = Funcs[Hash(Name) % HashSize];
	while (Func && !SEqual(Name, Func->GetName()))
		Func = Func->MapNext;
	return Func;
}
Beispiel #17
0
func Damage()
{
  if(SEqual(GetAction(),"An")) if(LessThan(50,GetDamage()))
  {
    SetAction("FlackerAn");
    if(!Local(0)) ObjectSetAction(Local(0)=CreateObject(LJ3V,-20,16),"Neon");
  }
  return(1);
}
bool C4PlayerList::CtrlRemoveAtClient(const char *szName, bool fDisconnect)
{
	// Get players
	for (C4Player *pPlr = First; pPlr; pPlr = pPlr->Next)
		if (SEqual(pPlr->AtClientName, szName))
			if (!CtrlRemove(pPlr->Number, fDisconnect))
				return false;
	return true;
}
C4Network2Res *C4Network2ResList::getRes(const char *szFile, bool fLocalOnly)
{
	CStdShareLock ResListLock(&ResListCSec);
	for (C4Network2Res *pCur = pFirst; pCur; pCur = pCur->pNext)
		if (!pCur->isAnonymous())
			if (SEqual(pCur->getFile(), szFile))
				if (!fLocalOnly || pCur->getResClient()==iClientID)
					return pCur;
	return NULL;
}
C4Network2Res::Ref C4Network2Res::Derive()
{
	// Called before the file is changed. Rescues all files and creates a
	// new resource for the file. This resource is flagged as "anonymous", as it
	// has no official core (no res ID, to be exact).
	// The resource gets its final core when FinishDerive() is called.

	// For security: This doesn't make much sense if the resource is currently being
	// loaded. So better assume the caller doesn't know what he's doing and check.
	if (isLoading()) return NULL;

	CStdLock FileLock(&FileCSec);
	// Save back original file name
	char szOrgFile[_MAX_PATH+1];
	SCopy(szFile, szOrgFile, _MAX_PATH);
	bool fOrgTempFile = fTempFile;

	// Create a copy of the file, if neccessary
	if (!*szStandalone || SEqual(szStandalone, szFile))
	{
		if (!pParent->FindTempResFileName(szOrgFile, szFile))
			{ Log("Derive: could not find free name for temporary file!"); return NULL; }
		if (!C4Group_CopyItem(szOrgFile, szFile))
			{ Log("Derive: could not copy to temporary file!"); return NULL; }
		// set standalone
		if (*szStandalone)
			SCopy(szFile, szStandalone, _MAX_PATH);
		fTempFile = true;
	}
	else
	{
		// Standlone exists: Just set szFile to point on the standlone. It's
		// assumed that the original file isn't of intrest after this point anyway.
		SCopy(szStandalone, szFile, _MAX_PATH);
		fTempFile = true;
	}

	Application.InteractiveThread.ThreadLogS("Network: Resource: deriving from %d:%s, original at %s", getResID(), Core.getFileName(), szFile);

	// (note: should remove temp file if something fails after this point)

	// create new resource
	C4Network2Res::Ref pDRes = new C4Network2Res(pParent);
	if (!pDRes) return NULL;

	// initialize
	if (!pDRes->SetDerived(Core.getFileName(), szOrgFile, fOrgTempFile, getType(), getResID()))
		return NULL;

	// add to list
	pParent->Add(pDRes);

	// return new resource
	return pDRes;
}
Beispiel #21
0
void C4MessageInput::StoreBackBuffer(const char *szMessage) {
  if (!szMessage || !szMessage[0]) return;
  int32_t i, cnt;
  // Check: Remove doubled buffer
  for (i = 0; i < C4MSGB_BackBufferMax - 1; ++i)
    if (SEqual(BackBuffer[i], szMessage)) break;
  // Move up buffers
  for (cnt = i; cnt > 0; cnt--) SCopy(BackBuffer[cnt - 1], BackBuffer[cnt]);
  // Add message
  SCopy(szMessage, BackBuffer[0], C4MaxMessage);
}
Beispiel #22
0
bool C4PhysicalInfo::GetOffsetByName(const char *szPhysicalName, Offset *pmpiOut)
	{
	// query map
	for (C4PhysInfoNameMap_t *entry = C4PhysInfoNameMap; entry->szName; ++entry)
		if (SEqual(entry->szName, szPhysicalName))
			{
			*pmpiOut = entry->off;
			return true;
			}
	return false;
	}
bool C4GraphicsOverlay::operator == (const C4GraphicsOverlay &rCmp) const
{
	// compare relevant fields
	// ignoring phase, because different animation state may be concatenated in graphics display
	return (eMode == rCmp.eMode)
	       && (pSourceGfx == rCmp.pSourceGfx)
	       && SEqual(Action, rCmp.Action)
	       && (dwBlitMode == rCmp.dwBlitMode)
	       && (dwClrModulation == rCmp.dwClrModulation)
	       && (Transform == rCmp.Transform)
	       && (OverlayObj == rCmp.OverlayObj);
}
Beispiel #24
0
void STest(char *value, char * expected, char * error) {
  // print report of failed test and exit
  S_TEST_ID++;
  if (!SEqual(value,expected)) {
    fprintf(stderr,"STest(%2d): failed - %s\n",S_TEST_ID,error);
    fprintf(stderr," value   : '%s'\n",value);
    fprintf(stderr," expected: '%s'\n",expected);
    exit(EXIT_FAILURE);
  } else 
    if (S_DEBUG_LEVEL >= 1)
      printf("STest(%2d): passed - %s\n",S_TEST_ID,error);
}
Beispiel #25
0
int32_t C4LandscapeRenderGL::LookupTextureTransition(const char *szFrom, const char *szTo)
{
	// Is this actually a transition? Otherwise we're looking for a single texture
	bool fTransit = !SEqual(szFrom, szTo);
	// Look for a position in the map where the textures appear in sequence
	uint32_t i;
	for(i = 1; i < MaterialTextureMap.size(); i++)
	{
		if(SEqual(szFrom, MaterialTextureMap[i].getData()))
		{
			// Single texture: We're done
			if(!fTransit) return i;
			// Check next texture as well
			if(i + 1 >= MaterialTextureMap.size())
				return -1;
			if(SEqual(szTo, MaterialTextureMap[i+1].getData()))
				return i;
		}
	}
	return -1;
}
Beispiel #26
0
void C4LandscapeRenderGL::AddTextureTransition(const char *szFrom, const char *szTo)
{
	// Empty?
	if (!szFrom || !szTo) return;
	// First try the lookup (both directions)
	if (LookupTextureTransition(szFrom, szTo) >= 0) return;
	if (LookupTextureTransition(szTo, szFrom) >= 0) return;
	// Single texture? Add it as single
	if (SEqual(szTo, szFrom))
		MaterialTextureMap.push_back(StdCopyStrBuf(szFrom));
	// Have one of the textures at the end of the list?
	else if(SEqual(MaterialTextureMap.back().getData(), szFrom))
		MaterialTextureMap.push_back(StdCopyStrBuf(szTo));
	else if(SEqual(MaterialTextureMap.back().getData(), szTo))
		MaterialTextureMap.push_back(StdCopyStrBuf(szFrom));
	else
	{
		// Otherwise add both
		MaterialTextureMap.push_back(StdCopyStrBuf(szFrom));
		MaterialTextureMap.push_back(StdCopyStrBuf(szTo));
	}
}
Beispiel #27
0
void C4ValueMapData::OnNameListChanged(const char **pOldNames, int32_t iOldSize)
{
	if(!pNames)
	{
		Reset();
		return;
	}

	// this function does not use ReAllocList because the old values
	// have to be hold.

	// save pointer on old data
	C4Value *pOldData = pData;

	// create new data list
	pData = new C4Value [pNames->iSize] ();

	// (try to) copy data
	int32_t i, j;
	for(i = 0; i < iOldSize; i++)
	{
		//FIXME: This optimization is ugly.
		if(i < pNames->iSize && SEqual(pNames->pNames[i], pOldNames[i]))
		{
			pOldData[i].Move(&pData[i]);
		}
		else for(j = 0; j < pNames->iSize; j++)
		{
			if(SEqual(pNames->pNames[j], pOldNames[i]))
			{
				pOldData[i].Move(&pData[j]);
				break; // in hope this will only break the last for...
			}
		}
	}
	// delete old data array
	delete[] pOldData;
}
Beispiel #28
0
void C4ValueMapData::OnNameListChanged(const char **pOldNames, int32_t iOldSize)
{
	if (!pNames)
	{
		Reset();
		return;
	}

	// this function does not use ReAllocList because the old values
	// have to be hold.

	// save pointer on old data
	C4Value *pOldData = pData;

	// create new data list
	pData = new C4Value [pNames->iSize] ();

	// (try to) copy data
	int32_t i, j;
	for (i = 0; i < iOldSize; i++)
	{
		if (i < pNames->iSize && SEqual(pNames->pNames[i], pOldNames[i]))
		{
			pData[i] = pOldData[i];
		}
		else for (j = 0; j < pNames->iSize; j++)
		{
			if (SEqual(pNames->pNames[j], pOldNames[i]))
			{
				pData[j] = pOldData[i];
				break;
			}
		}
	}
	// delete old data array
	delete[] pOldData;
}
Beispiel #29
0
int C4Shader::ParsePosition(const char *szWhat, const char **ppPos)
{
	const char *pPos = *ppPos;
	while (isspace(*pPos)) pPos++;

	// Expect a name
	const char *pStart = pPos;
	while (isalnum(*pPos)) pPos++;
	StdStrBuf Name; Name.Copy(pStart, pPos - pStart);

	// Lookup name
	int iPosition = -1;
	for (int i = 0; i < sizeof(C4SH_PosNames) / sizeof(*C4SH_PosNames); i++) {
		if (SEqual(Name.getData(), C4SH_PosNames[i].Name)) {
			iPosition = C4SH_PosNames[i].Position;
			break;
		}
	}
	if (iPosition == -1) {
		ShaderLogF("  gl: Unknown slice position in %s: %s", szWhat, Name.getData());
		return -1;
	}

	// Add modifier
	while (isspace(*pPos)) pPos++;
	if (*pPos == '+') {
		int iMod, iModLen;
		if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
			ShaderLogF("  gl: Invalid slice modifier in %s", szWhat);
			return -1;
		}
		iPosition += iMod;
		pPos += 1+iModLen;
	}
	if (*pPos == '-') {
		int iMod, iModLen;
		if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
			ShaderLogF("  gl: Invalid slice modifier in %s", szWhat);
			return -1;
		}
		iPosition -= iMod;
		pPos += 1+iModLen;
	}

	// Everything okay!
	*ppPos = pPos;
	return iPosition;
}
Beispiel #30
0
BOOL C4UpdatePackage::DoGrpUpdate(C4Group *pUpdateData, C4GroupEx *pGrpTo) {
    char *pData;
    // sort entries
    if (pUpdateData->LoadEntry(C4CFN_UpdateEntries, &pData, NULL, 1)) {
        // delete all entries that do not appear in the entries list
        char strItemName[_MAX_FNAME + 1], strItemName2[_MAX_FNAME + 1];
        pGrpTo->ResetSearch();
        while (pGrpTo->FindNextEntry("*", strItemName)) {
            BOOL fGotIt = FALSE;
            for (int i = 0;
                    fGotIt = SCopySegment(pData, i, strItemName2, '|', _MAX_FNAME);
                    i++) {
                // remove seperator
                char *pSep = strchr(strItemName2, '=');
                if (pSep) *pSep = '\0';
                // in list?
                if (SEqual(strItemName, strItemName2)) break;
            }
            if (!fGotIt) pGrpTo->DeleteEntry(strItemName);
        }
        // set entry times, set sort list
        char strSortList[32767] = "";
        for (int i = 0; SCopySegment(pData, i, strItemName, '|', _MAX_FNAME); i++) {
            // get time (if given)
            char *pTime = strchr(strItemName, '=');
            if (pTime) *pTime++ = '\0';
            // set
            if (pTime) pGrpTo->SetEntryTime(strItemName, atoi(pTime));
            // update EntryCRC32. This will make updates to old groups invalid
            // however, it's needed so updates will update the EntryCRC of *unchanged*
            // files correctly
            pGrpTo->EntryCRC32(strItemName);
            // copy to sort list
            SAppend(strItemName, strSortList);
            SAppendChar('|', strSortList);
        }
        // sort by list
        pGrpTo->Sort(strSortList);
        delete[] pData;
    }
    // copy header from update group
    pGrpTo->SetHead(*pUpdateData);
    // ok
    return TRUE;
}