/*=========================================================================== * * File: Dfcif.CPP * Author: Dave Humphrey (uesp@m0use.net) * Created On: Tuesday, June 26, 2001 * * Implements the CDFCifImage and CDFCifFile classes for handling the * Daggerfall CFI type image files. * *=========================================================================*/ /* Include Files */ #include "dfcif.h" /*=========================================================================== * * Begin Local Variable Definitions * *=========================================================================*/ DEFINE_FILE(); /*=========================================================================== * End of Local Variable Definitions *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean Read (void); * * Read a CIF image file from the current position in the file. Returns * FALSE on any error. * *=========================================================================*/ boolean CDFCifImage::Read (void) { DEFINE_FUNCTION("CDFCifImage::Read()"); boolean Result = TRUE; /* Ensure an open file */ ASSERT(IsOpen()); /* Read in the image header if required */ if (HasHeader()) Result = ReadHeader(); /* Skip the weapon CIF offset list, if present */ if (HasCIFOffsetList()) { Result = Seek(DFCIF_OFFSETLIST_SIZE, SEEK_CUR); } /* Read in the image data */ if (Result) { if (IsCompressed()) Result = ReadCompressedData(); else Result = ReadData(); } return (Result); } /*=========================================================================== * End of Class Method CDFCifImage::Read() *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean ReadCompressedData (void); * * Protected class method which reads in the compressed image data from * the current position in the file. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifImage::ReadCompressedData (void) { DEFINE_FUNCTION("CDFCifImage::ReadCompressedData()"); boolean Result; long BytesWritten = 0; int LoopCounter; int ByteCount; byte* pImagePtr; int Data; /* Ensure valid object state */ ASSERT(m_pData == NULL); /* Check for valid image size */ if (m_ImageSize <= 0 || (ulong)m_ImageSize >= (ulong) UINT_MAX) { ErrorHandler.AddError(DFERR_IMG_IMAGESIZE); return (FALSE); } /* Allocate the image data */ CreateArrayPointer(m_pData, byte, (size_t)m_ImageSize); pImagePtr = m_pData; /* Uncompress the data to image buffer */ while (BytesWritten < m_ImageSize) { ClearError(); Data = fgetc(GetHandle()); /* RLE type byte indicator */ if (Data > 0x7f) { ByteCount = (Data & 0xFF) - 0x7f; BytesWritten += ByteCount; Data = fgetc(GetHandle()); for (LoopCounter = 0; LoopCounter < ByteCount; LoopCounter++) { *pImagePtr = Data & 0xFF; pImagePtr++; } } /* Un-encoded pixel data */ else { ByteCount = (Data & 0xFF) + 1; BytesWritten += ByteCount; /* Read pixel values */ Result = CGenFile::Read((char *) pImagePtr, ByteCount); if (!Result) return (FALSE); pImagePtr += ByteCount; } /* Check for input errors */ if (IsError() || IsEOF()) { ErrorHandler.AddError(DFERR_IMG_READFILE); return (FALSE); } } /* End of while uncompressed data */ /* Check for buffer overwrites */ ASSERT(BytesWritten <= m_ImageSize); return (TRUE); } /*=========================================================================== * End of Class Method CDFCifImage::ReadCompressedData() *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean ReadHeader (void); * * Virtual protected class method to input the CIF image header data. * If the CIF image is a weapon file, the header is read appropiately, * otherwise the base class implementation is used. * *=========================================================================*/ boolean CDFCifImage::ReadHeader (void) { DEFINE_FUNCTION("CDFCifImage::ReadHeader()"); dfimgheader_t TempHeader; boolean Result; /* Ignore if not a weapon image */ if (!HasWeaponHeader()) return CDFImgFile::ReadHeader(); /* Input temporary 12 byte header */ Result = CGenFile::Read((char*)&TempHeader, sizeof(dfimgheader_t)); if (!Result) return (FALSE); /* Swap the image dimensions and offsets */ m_Header.Width = TempHeader.XOffset; m_Header.Height = TempHeader.YOffset; m_Header.XOffset = TempHeader.Width; m_Header.YOffset = TempHeader.Height; m_Header.Unknown = TempHeader.Unknown; m_Header.ImageSize = TempHeader.ImageSize; m_ImageSize = (long) m_Header.Width * (long) m_Header.Height; return (TRUE); } /*=========================================================================== * End of Class Method CDFCifImage::ReadHeader() *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean Write (void); * * Attempts to output the current image data to the current file stream. * Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifImage::Write (void) { DEFINE_FUNCTION("CDFCifImage::Write()"); boolean Result = TRUE; /* Ensure a valid file stream */ ASSERT(IsOpen()); /* Write the image header if required */ if (HasHeader()) Result = WriteHeader(); /* Skip the group offset list if required */ if (HasCIFOffsetList()) { if (Result) Result = Seek(DFCIF_OFFSETLIST_SIZE, SEEK_CUR); } /* Write the image data */ if (Result) { if (IsCompressed()) Result = WriteCompressedData(); else Result = WriteData(); } return (Result); } /*=========================================================================== * End of Class Method CDFCifImage::Write() *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean WriteCompressedData (void); * * Outputs RLE compressed data to the current position in the file stream. * Returns FALSE on any error. Protected class method. * *=========================================================================*/ boolean CDFCifImage::WriteCompressedData (void) { DEFINE_FUNCTION("CDFCifImage::WriteCompressedData()"); boolean ExtendedRLE; long BytesWritten; int ByteCount; short Column; short Row = 1; byte* pDataPtr; byte* pInitialData; byte PrevData; /* Ignore if nothing to write */ if (m_ImageSize == 0 || m_pData == NULL) return (TRUE); /* Check for valid image size */ if (m_ImageSize < 0 || (ulong)m_ImageSize >= (ulong) UINT_MAX) { ErrorHandler.AddError(DFERR_IMG_IMAGESIZE); return (FALSE); } /* Initialize the output variables */ pDataPtr = m_pData; PrevData = *pDataPtr; pDataPtr++; BytesWritten = 0; Column = 1; /* RLE compress the data to file */ while (BytesWritten < m_ImageSize) { ClearError(); /* Count number of sequential identical bytes */ if (*pDataPtr == PrevData) { ByteCount = 1; ExtendedRLE = FALSE; WRITE_RLE_BYTES: /* Count the number of repeated bytes */ while (*pDataPtr == PrevData && ByteCount <= 127 && Column < GetWidth()) { pDataPtr++; ByteCount++; Column++; } /* Special case for single byte */ if (ByteCount == 1) { if (PrevData == 0 && ExtendedRLE) fputc(0x80, GetHandle()); else fputc(0x00, GetHandle()); fputc((int)PrevData, GetHandle()); BytesWritten += 1; } else { /* Output 2-byte RLE code */ fputc(ByteCount + 127, GetHandle()); fputc((int)PrevData, GetHandle()); BytesWritten += ByteCount; } /* Check for more than 127 bytes of repeated data */ if (ByteCount > 127 && *pDataPtr == PrevData && Column < GetWidth()) { ByteCount = 0; ExtendedRLE = TRUE; goto WRITE_RLE_BYTES; } /* Move onto next data byte */ PrevData = *pDataPtr; pDataPtr++; Column++; } /* Output number of un-encoded bytes */ else { ByteCount = 0; pInitialData = pDataPtr - 1; /* Count the number of bytes to output */ while (*pDataPtr != PrevData && ByteCount <= 127 && Column < GetWidth()) { PrevData = *pDataPtr; pDataPtr++; ByteCount++; Column++; } /* End of column output */ if (Column >= GetWidth()) { PrevData = *pDataPtr; pDataPtr++; Column++; ByteCount++; } /* Output the un-encoded data points */ fputc(ByteCount-1, GetHandle()); fwrite(pInitialData, 1, ByteCount, GetHandle()); BytesWritten += ByteCount; } /* Check for output errors */ if (IsError() || IsEOF()) return (FALSE); /* End of column */ if (Column > GetWidth()) { Column = Column - GetWidth(); Row++; } } /* End of while writing image */ return (TRUE); } /*=========================================================================== * End of Class Method CDFCifImage::WriteCompressedData() *=========================================================================*/ /*=========================================================================== * * Class CDFCifImage Method - boolean WriteHeader (void); * * Virtual protected class method to output the CIF image header data. * If the CIF image is a weapon file, the header is written appropiately, * otherwise the base class implementation is used. * *=========================================================================*/ boolean CDFCifImage::WriteHeader (void) { DEFINE_FUNCTION("CDFCifImage::WriteHeader()"); dfimgheader_t TempHeader; boolean Result; /* Ignore if not a weapon image */ if (!HasWeaponHeader()) return CDFImgFile::WriteHeader(); /* Create temporary header */ TempHeader.Width = m_Header.XOffset; TempHeader.Height = m_Header.YOffset; TempHeader.XOffset = m_Header.Width; TempHeader.YOffset = m_Header.Height; TempHeader.Unknown = m_Header.Unknown; TempHeader.ImageSize = m_Header.ImageSize; /* Output temporary 12 byte header */ Result = CGenFile::Write((char*)&TempHeader, sizeof(dfimgheader_t)); if (!Result) return (FALSE); return (TRUE); } /*=========================================================================== * End of Class Method CDFCifImage::WriteHeader() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Constructor * *=========================================================================*/ CDFCifFile::CDFCifFile() { m_NumImages = 0; m_Flags = 0; m_GroupCounter = 0; } /*=========================================================================== * End of Class CDFCifFile Constructor *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Destructor * *=========================================================================*/ void CDFCifFile::Destroy (void) { DEFINE_FUNCTION("CDFCifFile::Destroy()"); int LoopCounter; /* Destroy all allocated images */ for (LoopCounter = 0; LoopCounter < m_NumImages; LoopCounter++) { DestroyPointer(m_pImages[LoopCounter]); } m_NumImages = 0; m_Flags = 0; m_GroupCounter = 0; } /*=========================================================================== * End of Class CDFCifFile Destructor *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean IsWeaponCIFFilename (pFilename); * * Static class method which checks if the given filename is a weapon * type CIF. The filename, minus the path and extension is examined for * the format: * WEAPON##.CIF or WEAPO###.CIF * * where ### represents a base-10 number. * *=========================================================================*/ boolean CDFCifFile::IsWeaponCIFFilename (const char* pFilename) { DEFINE_FUNCTION("CDFCifFile::IsWeaponCIFFilename()"); char TempFilename[_MAX_PATH+1]; int Value; /* Ensure valid input */ ASSERT(pFilename != NULL); /* Remove the path and extension from input filename */ ExtractFilename(TempFilename, pFilename, _MAX_PATH); RemoveExtension(TempFilename); /* Check for the "WEAPON##" format */ if (strnicmp(TempFilename, "WEAPON", 6) == 0) { Value = atoi(TempFilename + 6); if (Value <= 0 || Value > 99) return (FALSE); return (TRUE); } /* Check for the "WEAPO###" format */ else if (strnicmp(TempFilename, "WEAPO", 5) == 0) { Value = atoi(TempFilename + 5); if (Value <= 0 || Value > 999) return (FALSE); return (TRUE); } /* Otherwise it's not a weapon cif file */ return (FALSE); } /*=========================================================================== * End of Class Method CDFCifFile::IsWeaponCIFFilename() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean Load (pFilename); * * Attempts to read in the given CIF file. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::Load (const char* pFilename) { DEFINE_FUNCTION("CDFCifFile::Load()"); boolean Result; /* Attempt to open file for input */ Result = Open(pFilename, "rb"); if (!Result) return (FALSE); /* Read a regular or weapon CIF file */ if (IsWeaponCIFFilename(pFilename)) Result = ReadWeaponCIF(); else Result = ReadCIF(); Close(); return (Result); } /*=========================================================================== * End of Class Method CDFCifFile::Load() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean Save (pFilename); * * Attempts to save the given CIF file. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::Save (const char* pFilename) { DEFINE_FUNCTION("CDFCifFile::Save()"); boolean Result; /* Attempt to open file for output */ Result = CGenFile::Open(pFilename, "wb"); if (!Result) return (FALSE); /* Read a regular or weapon CIF file */ if (IsWeaponCIFFilename(pFilename)) Result = WriteWeaponCIF(); else Result = WriteCIF(); Close(); return (Result); } /*=========================================================================== * End of Class Method CDFCifFile::Save() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean ReadCIF (void); * * Attempts to read in a regular CIF file. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::ReadCIF (void) { DEFINE_FUNCTION("CDFCifFile::ReadCIF"); long FileSize; boolean Result; /* Destroy the current image information */ Destroy(); /* Get the filesize */ Result = GetFileSize(FileSize); if (!Result) return (FALSE); /* Read in image data until no more left */ while (FileSize - Tell() >= DFCIF_MINBYTES_LEFT) { /* Ensure we don't load too many images */ if (m_NumImages >= DFCIF_MAX_IMAGES) { ErrorHandler.AddError(DFERR_CIF_MAXIMAGES); return (FALSE); } /* Allocate the image data */ CreatePointer(m_pImages[m_NumImages], CDFCifImage); m_pImages[m_NumImages]->SetWeaponCIF(FALSE); /* Special case for FACES.CIF */ if (FileSize == 249856l) { m_pImages[m_NumImages]->SetHasHeader(FALSE); m_pImages[m_NumImages]->SetWidth(64); m_pImages[m_NumImages]->SetHeight(64); m_pImages[m_NumImages]->SetImageSize(4096l); } /* Read in the image file */ m_pImages[m_NumImages]->Attach(GetHandle()); Result = m_pImages[m_NumImages]->Read(); m_pImages[m_NumImages]->Detach(); m_NumImages++; if (!Result) return (FALSE); } /* Check for extra bytes left in CIF file */ if (FileSize - Tell() != 0) SystemLog.Printf ("\t\tPossible under read of CIF image file (%ld bytes)!", FileSize - Tell()); return (TRUE); } /*=========================================================================== * End of Class Method CDFCifFile::ReadCIF() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean ReadFirstWeaponImage (void); * * Reads the first weapon image in the CIF file, if there is any. * Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::ReadFirstWeaponImage (void) { DEFINE_FUNCTION("CDFCifFile::ReadFirstWeaponImage()"); boolean Result; char InputChar; /* Ensure valid object state */ ASSERT(m_NumImages == 0); /* Move to 9th character and read */ Result = Seek(8, SEEK_SET); if (Result) Result = ReadChar(InputChar); if (Result) Result = Seek(0, SEEK_SET); if (!Result) return (FALSE); /* Check for special character byte */ if (InputChar == 0x15) { SetHasFirstImage(FALSE); return (TRUE); } /* Allocate the first image */ CreatePointer(m_pImages[0], CDFCifImage); /* Initialize the image properties */ m_pImages[0]->SetCIFGroup(m_GroupCounter); m_NumImages = 1; m_GroupCounter++; /* Read the first image data */ m_pImages[0]->Attach(GetHandle()); Result = m_pImages[0]->Read(); m_pImages[0]->Detach(); return (Result); } /*=========================================================================== * End of Class Method CDFCifFile::ReadFirstWeaponImage() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean ReadWeaponGroup (void); * * Inputs one group of images from the current CIF file. Returns FALSE * on any error. * *=========================================================================*/ boolean CDFCifFile::ReadWeaponGroup (void) { DEFINE_FUNCTION("CDFCifFile::ReadWeaponGroup()"); long GroupOffset; ushort GroupOffsetList[DFCIF_NUM_OFFSETS]; int NumGroupImages; int LoopCounter; boolean Result; /* Save the group file offset */ GroupOffset = Tell(); /* Allocate and initialize first group image */ CreatePointer(m_pImages[m_NumImages], CDFCifImage); m_pImages[m_NumImages]->SetCIFOffsetList(TRUE); m_pImages[m_NumImages]->SetWeaponHeader(TRUE); m_pImages[m_NumImages]->SetCompressed(TRUE); m_pImages[m_NumImages]->SetCIFGroup(m_GroupCounter); /* Read in the first image in the group */ m_pImages[m_NumImages]->Attach(GetHandle()); Result = m_pImages[m_NumImages]->Read(); m_pImages[m_NumImages]->Detach(); m_NumImages++; if (!Result) return (FALSE); Result = Seek(GroupOffset + 12, SEEK_SET); if (Result) Result = Read((char*)&GroupOffsetList[0], sizeof(short)*DFCIF_NUM_OFFSETS); if (!Result) return (FALSE); /* Count the number of subimages in the group */ for (NumGroupImages = 0; NumGroupImages < DFCIF_NUM_OFFSETS; NumGroupImages++) { if (GroupOffsetList[NumGroupImages] == 0) break; } /* Read in each sub-image in group (first image already read) */ for (LoopCounter = 1; LoopCounter < NumGroupImages; LoopCounter++) { /* Jump to start of image data and read */ Result = Seek(GroupOffset + GroupOffsetList[LoopCounter], SEEK_SET); if (Result) Result = ReadWeaponGroupImage(); if (!Result) return (FALSE); } /* Move to the start of the next image group */ Result = Seek(GroupOffsetList[DFCIF_NUM_OFFSETS-1] + GroupOffset, SEEK_SET); m_GroupCounter++; return (Result); } /*=========================================================================== * End of Class Method CDFCifFile::ReadWeaponGroup() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean ReadWeaponGroupImage (void); * * Reads one subimage from the current weapon group. Returns FALSE on * any error. Protected class method. * *=========================================================================*/ boolean CDFCifFile::ReadWeaponGroupImage (void) { DEFINE_FUNCTION("CDFCifFile::ReadWeaponGroupImage()"); boolean Result; long ImageSize; /* Ensure a valid object state */ ASSERT(m_NumImages > 0); /* Ensure we don't create too many images to overflow image array */ if (m_NumImages >= DFCIF_MAX_IMAGES) { ErrorHandler.AddError(DFERR_CIF_MAXIMAGES); return (FALSE); } /* Allocate and initialize the image (no header) */ CreatePointer(m_pImages[m_NumImages], CDFCifImage); m_pImages[m_NumImages]->SetHasHeader(FALSE); m_pImages[m_NumImages]->SetCompressed(TRUE); m_pImages[m_NumImages]->SetCIFGroup(m_GroupCounter); m_pImages[m_NumImages]->SetWidth(m_pImages[m_NumImages-1]->GetWidth()); m_pImages[m_NumImages]->SetHeight(m_pImages[m_NumImages-1]->GetHeight()); ImageSize = (long) m_pImages[m_NumImages-1]->GetWidth() * (long)m_pImages[m_NumImages-1]->GetHeight(); m_pImages[m_NumImages]->SetImageSize(ImageSize); m_NumImages++; /* Read image data */ m_pImages[m_NumImages-1]->Attach(GetHandle()); Result = m_pImages[m_NumImages-1]->Read(); m_pImages[m_NumImages-1]->Detach(); if (!Result) return (FALSE); return (TRUE); } /*=========================================================================== * End of Class Method CDFCifFile::ReadWeaponGroupImage() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean ReadWeaponCIF (void); * * Attempts to read in the weapon CIF file. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::ReadWeaponCIF (void) { DEFINE_FUNCTION("CDFCifFile::ReadWeaponCIF()"); long FileSize; boolean Result; /* Destroy the current image information */ Destroy(); SetWeaponCIF(TRUE); m_GroupCounter = 0; /* Get the filesize and read the first weapon CIF image, if any */ Result = GetFileSize(FileSize); if (Result) Result = ReadFirstWeaponImage(); if (!Result) return (FALSE); /* Read in weapon CIF images until no more left */ while (FileSize - Tell() >= DFCIF_MINBYTES_LEFT) { /* Ensure we don't load too many images */ if (m_NumImages >= DFCIF_MAX_IMAGES) { ErrorHandler.AddError(DFERR_CIF_MAXIMAGES); return (FALSE); } /* Input the group of weapon images */ Result = ReadWeaponGroup(); if (!Result) return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CDFCifFile::ReadWeaponCIF() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean WriteCIF (void); * * Protected class method to output a CIF file to the current file stream. * Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::WriteCIF (void) { DEFINE_FUNCTION("CDFCifFile::WriteCIF()"); int Index; boolean Result; /* Write all image data */ for (Index = 0; Index < m_NumImages; Index++) { /* Write the image file */ m_pImages[Index]->Attach(GetHandle()); Result = m_pImages[Index]->Write(); m_pImages[Index]->Detach(); if (!Result) return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CDFCifFile::WriteCIF() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean WriteWeaponCIF (void); * * Protected class method to output a weapon CIF file to the current * file stream. Returns FALSE on any error. * *=========================================================================*/ boolean CDFCifFile::WriteWeaponCIF (void) { DEFINE_FUNCTION("CDFCifFile::WriteWeaponCIF()"); int Index = 0; boolean Result; /* Output the first weapon image, if any */ if (HasFirstImage()) { m_pImages[0]->Attach(GetHandle()); Result = m_pImages[0]->Write(); m_pImages[0]->Detach(); if (!Result) return (FALSE); Index = 1; } /* Write all weapon CIF images */ while (Index < m_NumImages) { /* Output the group of weapon images */ Result = WriteWeaponGroup(Index); if (!Result) return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CDFCifFile::WriteWeaponCIF() *=========================================================================*/ /*=========================================================================== * * Class CDFCifFile Method - boolean WriteWeaponGroup (Index); * * Outputs a weapon group starting at the given image index. Modifies * the index on return to point to the next image. Returns FALSE on * any error. Protected class method. * *=========================================================================*/ boolean CDFCifFile::WriteWeaponGroup (int& ImageIndex) { DEFINE_FUNCTION("CDFCifFile::WriteWeaponGroup()"); long GroupOffset; ushort GroupOffsetList[DFCIF_NUM_OFFSETS]; int OffsetIndex; int GroupIndex; boolean Result; /* Ensure valid input */ ASSERT(ImageIndex >= 0 && ImageIndex < m_NumImages); /* Save the group file offset */ GroupOffset = Tell(); GroupIndex = m_pImages[ImageIndex]->GetCIFGroup(); memset(GroupOffsetList, 0, sizeof(ushort)*DFCIF_NUM_OFFSETS); /* Write the first image in the group */ m_pImages[ImageIndex]->Attach(GetHandle()); Result = m_pImages[ImageIndex]->Write(); m_pImages[ImageIndex]->Detach(); if (!Result) return (FALSE); /* Initialize the output variables */ GroupOffsetList[0] = 76; OffsetIndex = 1; ImageIndex++; /* Output each image in the group */ while (ImageIndex < m_NumImages && m_pImages[ImageIndex]->GetCIFGroup() == GroupIndex) { /* Update the group offset list */ GroupOffsetList[OffsetIndex] = (ushort)(Tell() - GroupOffset); /* Write the image data */ m_pImages[ImageIndex]->Attach(GetHandle()); Result = m_pImages[ImageIndex]->Write(); m_pImages[ImageIndex]->Detach(); if (!Result) return (FALSE); ImageIndex++; OffsetIndex++; } /* Update and write group offset */ GroupOffsetList[DFCIF_NUM_OFFSETS-1] = (ushort) (Tell() - GroupOffset); Result = Seek(GroupOffset + 12, SEEK_SET); if (Result) Result = CGenFile::Write((char *) &GroupOffsetList[0], DFCIF_NUM_OFFSETS*sizeof(ushort)); if (!Result) return (FALSE); /* Move to the start of the next image group */ Result = Seek(GroupOffsetList[DFCIF_NUM_OFFSETS-1] + GroupOffset, SEEK_SET); return (Result); } /*=========================================================================== * End of Class Method CDFCifFile::WriteWeaponGroup() *=========================================================================*/