public bool ExportImage(RoGrfFileItem grfItem) { byte[] imageData = grfItem.FileData; try { using (MemoryStream ms = new MemoryStream(imageData)) { using (Bitmap bmp = (Bitmap)Bitmap.FromStream(ms)) { // Replace fuchsia (255, 0, 255) bmp.MakeTransparent(Color.Fuchsia); bmp.Save(Imagepath); } } } catch (Exception ex) { return false; } return true; }
/// <summary> /// Reads the uncompressed body of versions equal or above 0x200. /// The body is ZIP (deflate) compressed. /// </summary> /// <param name="binReader"></param> /// <param name="fileCount"></param> /// <param name="skipFiles"></param> /// <returns></returns> private bool ReadFilesVersion2(BinaryReader binReader, int fileCount, bool skipFiles) { int lengthCompressed = binReader.ReadInt32(); int lengthUnCompressed = binReader.ReadInt32(); mFileTableLength = (ulong)lengthUnCompressed; var bufCompressed = new byte[lengthCompressed]; mFiletableUncompressed = new byte[(int)mFileTableLength]; binReader.Read(bufCompressed, 0, lengthCompressed); mFiletableUncompressed = Deflate.Decompress(bufCompressed); /* if (mFiletableUncompressed.Length != (int)mFileTableLength) { throw new Exception("Filesize missmatch! Uncompressed Body Size is not equal to Uncompressed Length!"); } */ // Only read body? if (skipFiles == false) { for (int i = 0, offset = 0; i < fileCount; i++) { var filepath = string.Empty; char c; var itemTableOffset = (uint)offset; while ((c = (char)mFiletableUncompressed[offset++]) != '\0') { filepath += c; } filepath = Tools.UnifyPath(filepath); var item = new RoGrfFileItem { TableOffset = itemTableOffset, Index = Files.Count, Filepath = filepath, Flags = mFiletableUncompressed[offset + 12] }; // File or directory? if (item.IsFile) { item.LengthCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset); item.LengthCompressedAlign = BitConverter.ToUInt32(mFiletableUncompressed, offset + 4); item.LengthUnCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset + 8); // Offset is base offset + grf header item.DataOffset = BitConverter.ToUInt32(mFiletableUncompressed, offset + 13) + GrfHeaderLen; // from eAtehna, DES encryption item.Cycle = 1; switch (item.Flags) { case 3: for (var lop = 10; item.LengthCompressed >= lop; lop = lop * 10, item.Cycle++) { } break; case 5: item.Cycle = 0; break; default: item.Cycle = -1; break; } } else { // skip dirs offset += (int)GrfFileLen; continue; } // FIX: Some files in a tested grf are duplicated? // I cant remember grf version or something else.. if (GetFileByHash(item.NameHash) != null) { // Duplicate file, just skip it offset += (int)GrfFileLen; continue; } Files.Add(item.NameHash, item); mStringlist.Add(item.NameHash); mFileDataLength += item.LengthCompressedAlign; offset += (int)GrfFileLen; #if !DISABLE_GRF_EVENTS OnItemAdded(item, i, fileCount); #endif } } return true; }
/// <summary> /// Reads the uncompressed body of versions between 0x100 and 0x103. /// No compression of the body but a mess on filenames. /// </summary> /// <param name="binReader"></param> /// <param name="fileCount"></param> /// <param name="skipFiles"></param> /// <returns></returns> private bool ReadFilesVersion1(BinaryReader binReader, int fileCount, bool skipFiles) { mFileTableLength = (ulong)(binReader.BaseStream.Length - binReader.BaseStream.Position); mFiletableUncompressed = binReader.ReadBytes((int)mFileTableLength); // Read only body? if (skipFiles == false) { for (int i = 0, offset = 0; i < fileCount; i++) { var itemTableOffset = (uint)offset; var entryType = mFiletableUncompressed[offset + 12]; var offset2 = offset + BitConverter.ToInt32(mFiletableUncompressed, offset) + 4; if (entryType == 0) { offset = offset2 + 17; continue; } var nameLen = mFiletableUncompressed[offset] - 6; // These are client limits if (nameLen >= GrfMaxFilenameLength) { throw new Exception("Filename on index " + i + " is " + nameLen + " bytes long, max length is " + GrfMaxFilenameLength + "."); } var nameBuf = new byte[nameLen]; Buffer.BlockCopy(mFiletableUncompressed, offset + 6, nameBuf, 0, nameLen); var name = RoGrfHelper.DecodeFileName(nameBuf); // Check and fix the filename if (name.Contains('\0')) { name = name.Substring(0, name.IndexOf('\0')); } var compressedLenAligned = (uint)(BitConverter.ToInt32(mFiletableUncompressed, offset2 + 4) - 37579); var realLen = (uint)BitConverter.ToInt32(mFiletableUncompressed, offset2 + 8); var pos = (uint)BitConverter.ToInt32(mFiletableUncompressed, offset2 + 13); var cycle = 0; var compressedLen = 0; if (name.Contains(".")) { var ext = "." + name.Split('.').Last().ToLower(); compressedLen = BitConverter.ToInt32(mFiletableUncompressed, offset2) - BitConverter.ToInt32(mFiletableUncompressed, offset2 + 8) - 715; if (ext != ".gnd" && ext != ".gat" && ext != ".act" && ext != ".str") { cycle = 1; for (int j = 10; compressedLen >= j; j *= 10) cycle++; } } name = Tools.UnifyPath(name); var item = new RoGrfFileItem { TableOffset = itemTableOffset, Index = Files.Count, Filepath = name, LengthCompressed = (uint)compressedLen, LengthCompressedAlign = compressedLenAligned, LengthUnCompressed = realLen, Flags = entryType, // base offset + header length DataOffset = pos + GrfHeaderLen }; Files.Add(item.NameHash, item); mStringlist.Add(item.NameHash); mFileDataLength += item.LengthCompressedAlign; offset += (int)GrfFileLen; #if !DISABLE_GRF_EVENTS OnItemAdded(item, i, fileCount); #endif } } return true; }
public bool ExportImage(RoGrfFileItem grfItem) { byte[] spriteData = grfItem.FileData; string sprFilepath = Path.GetTempFileName(); File.WriteAllBytes(sprFilepath, spriteData); spriteData = null; try { using (RoSprite sprFile = new RoSprite(sprFilepath)) { sprFile.DrawImage(0); using (Bitmap bmp = sprFile.GetImageTransparent(0)) { bmp.Save(Environment.CurrentDirectory + @"\data\mobs\" + ID + ".png"); } } } catch (Exception ex) { return false; } return true; }
private void mGrfFile_ItemAdded(RoGrfFileItem item, int percent) { mBackgroundLoading.ReportProgress(percent, item); }
/// <summary> /// Triggers the ItemAdded event. /// </summary> /// <param name="item"></param> /// <param name="num"></param> /// <param name="maxCount"></param> public void OnItemAdded(RoGrfFileItem item, int num, int maxCount) { if (ItemAdded == null) { return; } var p = (int)(((float)num / maxCount) * 100); if (p == mCurrentItemPercent) { return; } mCurrentItemPercent = p; ItemAdded(item, p); }
/// <summary> /// Returns the file data, decompressed if needed /// </summary> /// <param name="item">The grf file</param> /// <param name="decompress">Should the data decompressed?</param> /// <returns></returns> public byte[] GetFileData(RoGrfFileItem item, bool decompress) { byte[] buf = null; bool isUpdated = item.IsAdded || item.IsUpdated; if (isUpdated) { // Load data from file buf = File.ReadAllBytes(item.NewFilepath); } else if (item.FileData == null || item.FileData.Length != item.LengthCompressedAlign) { // Cache data CacheFileData(item); buf = item.FileData; } if (isUpdated == false && buf != null && buf.Length > 0) { // deocde, if needed if (item.Cycle >= 0 && Deflate.IsMagicHead(buf) == false) { RoGrfHelper.DecryptFileData(buf, item.Cycle == 0, item.Cycle); } // Decompress data if (decompress) { buf = Deflate.Decompress(buf); } } return buf; }
/// <summary> /// Extract the file data to the given path /// <para>Note: the full path will be RootFolder + FilePath</para> /// </summary> /// <param name="rootFolder">The lokal root to save the data</param> /// <param name="item">The grf file</param> /// <param name="clearData">Should the data be cleaned (item.Flush()) after writing?</param> public void ExtractFile(string rootFolder, RoGrfFileItem item, bool clearData) { ExtractFile(rootFolder, item, clearData, false); }
private void AddFile(string filepath, bool refresh = true) { var newItem = new RoGrfFileItem(); newItem.LoadFromFile(mGrfFile, filepath); // Try getting clone of exsting item // Used to refresh the item list after an update string nameHash = newItem.NameHash; var existingItem = mGrfFile.GetFileByHash(nameHash); OLVListItem existingListItem = null; if (existingItem != null) { existingListItem = listView.ModelToItem(existingItem); } // Add the item ERoGrfFileItemState result = mGrfFile.AddFile(newItem); // Added a new item to the grf? if (result == ERoGrfFileItemState.Added) { listView.AddObject(newItem); } else if (result == ERoGrfFileItemState.Updated) { // Updated an item, try get the origin if (existingListItem != null) { existingListItem.RowObject = mGrfFile.GetFileByHash(newItem.NameHash); listView.RefreshItem(existingListItem); } } // Refresh info if (refresh) { SetGrfInfo(); } newItem = null; }
private int GetItemImageIndex(RoGrfFileItem grfItem) { // Default to "data" int index = 0; if (grfItem == null) { return index; } // New file if (grfItem.IsAdded) { return 5; } // Updated file if (grfItem.IsUpdated) { return 6; } int extIndex = grfItem.Filepath.LastIndexOf('.'); if (extIndex == -1) { // Dir return 4; } // Extension without leading dot switch (grfItem.Filepath.Substring(extIndex + 1).ToLower()) { case "txt": case "lua": index = 1; break; case "jpg": case "jepg": case "png": case "bmp": case "tga": index = 2; break; case "wav": case "mp3": index = 3; break; } return index; }
private void SetPreview(RoGrfFileItem grfItem) { HidePreviewControls(); // No selection or selected a dir; or empty items (possible?) if (grfItem == null || grfItem.Flags == 0 || (grfItem.IsAdded == false && grfItem.IsUpdated == false && grfItem.FileData != null && grfItem.FileData.Length == 0)) { return; } int extIndex = grfItem.Filepath.LastIndexOf('.'); if (extIndex == -1) { // Maybe a directory return; } // Ensure data got loaded and decompressed byte[] buf = mGrfFile.GetFileData(grfItem, true); // Get extension without leading dot string ext = grfItem.Filepath.Substring(extIndex + 1).ToLower(); // Will be true, if list view should be blocked until preview control released it bool blockListView = false; if (buf != null && buf.Length > 0) { foreach (var p in mPlugins) { var previewPanel = p as IPreviewPanel; if (previewPanel == null || previewPanel.IsSupported(ext) == false) { continue; } previewPanel.SetData(buf, Path.GetFileNameWithoutExtension(grfItem.Filepath)); var control = p as Control; if (control != null) { control.Visible = true; } if (previewPanel.BlockListView()) { blockListView = true; } break; } if (blockListView) { // Block listView selecting new items until pewview is ready listView.Enabled = false; } } // if(buf != null && buf.Length > 0) buf = null; grfItem.Flush(); mSelectedGrfItem = grfItem; }
private void FillListView() { var grfItems = new RoGrfFileItem[mGrfFile.Files.Count]; mGrfFile.Files.Values.CopyTo(grfItems, 0); listView.ClearCachedInfo(); listView.SetObjects(grfItems); grfItems = null; }
private void OpenGrf(string filepath) { listView.DeselectAll(); mSelectedGrfItem = null; mGrfFilepath = filepath; SetGuiState(false); SetInfoState("Opening GRF: " + filepath, Resources.information); lblStatusProgress.Visible = true; lblGrfInfo.Visible = false; if (TaskbarManager.IsPlatformSupported) { mWin7Taskbar.SetProgressState(TaskbarProgressBarState.Normal); mWin7Taskbar.SetProgressValue(0, 100); } mBackgroundLoading.RunWorkerAsync(); }
private void mGrfFile_ItemWrite(RoGrfFileItem item, int percent) { mBackgroundSaving.ReportProgress(percent, item); }
/// <summary> /// Add the grf file to the internal lists /// <para>Note: File will be deleted and a clone added if the file already exists</para> /// </summary> /// <param name="item">The grf file</param> /// <returns>The new item state</returns> public ERoGrfFileItemState AddFile(RoGrfFileItem item) { RoGrfFileItem existingItem; bool replaceExistingItem = false; if ((existingItem = GetFileByHash(item.NameHash)) != null) { // Replace old item if (existingItem.IsAdded) { // A newly added item should be replaced.. // Remove it and add as new one DeleteFile(existingItem); replaceExistingItem = true; } else { // Update existing item with new uncompressed data existingItem.State |= ERoGrfFileItemState.Updated; // Mark as not deleted existingItem.State &= ~ERoGrfFileItemState.Deleted; // Check for file data if (item.IsAdded && item.NewFilepath != null && File.Exists(item.NewFilepath)) { existingItem.NewFilepath = item.NewFilepath; } else if (item.FileData != null) { // Save data in tmp file string tmpFilepath = Path.GetTempPath(); File.WriteAllBytes(tmpFilepath, item.FileData); existingItem.NewFilepath = tmpFilepath; } else { throw new Exception("Unable to fetch item data."); } // Updated compressed length existingItem.LengthCompressed = (uint)new FileInfo(existingItem.NewFilepath).Length; existingItem.FileData = new byte[0]; // Inform the client about the update of an existing item return ERoGrfFileItemState.Updated; } } var newItem = item.Clone() as RoGrfFileItem; if (newItem == null) { throw new Exception("Failed to clone item."); } // Realy new item or just a replace? if (replaceExistingItem) { // Just replace the reference newItem.State = ERoGrfFileItemState.Updated; Files[newItem.NameHash] = newItem; } else { // Add new item newItem.State = ERoGrfFileItemState.Added; Files.Add(newItem.NameHash, newItem); mStringlist.Add(newItem.NameHash); } // Okay, this is handy.. // we return true, because the file was added as new item // buuut.. if the file was previously found AND the existing one was a NEW file // the new file will be deleted and the new one added // // so we need to "fake" the result, because of we dont add a new one // we replace the existing one.. // complicated.. if (replaceExistingItem) { // We didnt add a new item return ERoGrfFileItemState.Updated; } return ERoGrfFileItemState.Added; }
/// <summary> /// Removes the given file from internal lists /// The grf needs to be saved to save the changes /// </summary> /// <param name="item">The grf file</param> public void DeleteFile(RoGrfFileItem item) { DeleteFile(RoGrfFileItem.BuildNameHash(item.Filepath)); }
/// <summary> /// Reads the uncompressed body of versions between 0x100 and 0x103. /// No compression of the body but a mess on filenames. /// </summary> /// <param name="binReader"></param> /// <param name="fileCount"></param> /// <param name="skipFiles"></param> /// <returns></returns> private bool ReadFilesVersion1(BinaryReader binReader, int fileCount, bool skipFiles) { mFileTableLength = (ulong)(binReader.BaseStream.Length - binReader.BaseStream.Position); mFiletableUncompressed = binReader.ReadBytes((int)mFileTableLength); // Read only body? if (skipFiles == false) { for (int i = 0, offset = 0; i < fileCount; i++) { var itemTableOffset = (uint)offset; var entryType = mFiletableUncompressed[offset + 12]; var offset2 = offset + BitConverter.ToInt32(mFiletableUncompressed, offset) + 4; if (entryType == 0) { offset = offset2 + 17; continue; } var nameLen = mFiletableUncompressed[offset] - 6; // These are client limits if (nameLen >= GrfMaxFilenameLength) { throw new Exception("Filename on index " + i + " is " + nameLen + " bytes long, max length is " + GrfMaxFilenameLength + "."); } var nameBuf = new byte[nameLen]; Buffer.BlockCopy(mFiletableUncompressed, offset + 6, nameBuf, 0, nameLen); var name = RoGrfHelper.DecodeFileName(nameBuf); // Check and fix the filename if (name.Contains('\0')) { name = name.Substring(0, name.IndexOf('\0')); } var compressedLenAligned = (uint)(BitConverter.ToInt32(mFiletableUncompressed, offset2 + 4) - 37579); var realLen = (uint)BitConverter.ToInt32(mFiletableUncompressed, offset2 + 8); var pos = (uint)BitConverter.ToInt32(mFiletableUncompressed, offset2 + 13); var cycle = 0; var compressedLen = 0; if (name.Contains(".")) { var ext = "." + name.Split('.').Last().ToLower(); compressedLen = BitConverter.ToInt32(mFiletableUncompressed, offset2) - BitConverter.ToInt32(mFiletableUncompressed, offset2 + 8) - 715; if (ext != ".gnd" && ext != ".gat" && ext != ".act" && ext != ".str") { cycle = 1; for (int j = 10; compressedLen >= j; j *= 10) { cycle++; } } } name = Tools.UnifyPath(name); var item = new RoGrfFileItem { TableOffset = itemTableOffset, Index = Files.Count, Filepath = name, LengthCompressed = (uint)compressedLen, LengthCompressedAlign = compressedLenAligned, LengthUnCompressed = realLen, Flags = entryType, // base offset + header length DataOffset = pos + GrfHeaderLen }; Files.Add(item.NameHash, item); mStringlist.Add(item.NameHash); mFileDataLength += item.LengthCompressedAlign; offset += (int)GrfFileLen; #if !DISABLE_GRF_EVENTS OnItemAdded(item, i, fileCount); #endif } } return(true); }
/// <summary> /// Extract the file data to the given path /// <para>Note: The FilePath will be ignored if ignoreFilePath is set to true</para> /// </summary> /// <param name="rootFolder">The lokal root to save the data</param> /// <param name="item">The grf file</param> /// <param name="clearData">Should the data be cleaned (item.Flush()) after writing?</param> /// <param name="ignoreFilePath">Ignore item filepath?</param> public void ExtractFile(string rootFolder, RoGrfFileItem item, bool clearData, bool ignoreFilePath) { if (item.Flags == 0 || item.IsAdded) { return; } byte[] data = GetFileData(item, true); rootFolder = Tools.UnifyPath(rootFolder); if (rootFolder.EndsWith("/") == false) { rootFolder += "/"; } string extractDir = rootFolder; if (ignoreFilePath == false) { extractDir = Path.Combine(extractDir, Tools.UnifyPath(Path.GetDirectoryName(item.Filepath))); } if (Directory.Exists(extractDir) == false) { Directory.CreateDirectory(extractDir); } var filename = Path.GetFileName(item.Filepath); if (string.IsNullOrEmpty(filename)) { throw new Exception("Unable to extract filename from item filepath: " + item.Filepath); } var extractFilepath = Path.Combine(extractDir, filename); try { if (File.Exists(extractFilepath)) { File.Delete(extractFilepath); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } File.WriteAllBytes(extractFilepath, data); if (clearData) { item.FileData = null; } }
/// <summary> /// Reads the uncompressed body of versions equal or above 0x200. /// The body is ZIP (deflate) compressed. /// </summary> /// <param name="binReader"></param> /// <param name="fileCount"></param> /// <param name="skipFiles"></param> /// <returns></returns> private bool ReadFilesVersion2(BinaryReader binReader, int fileCount, bool skipFiles) { int lengthCompressed = binReader.ReadInt32(); int lengthUnCompressed = binReader.ReadInt32(); mFileTableLength = (ulong)lengthUnCompressed; var bufCompressed = new byte[lengthCompressed]; mFiletableUncompressed = new byte[(int)mFileTableLength]; binReader.Read(bufCompressed, 0, lengthCompressed); mFiletableUncompressed = Deflate.Decompress(bufCompressed); /* * if (mFiletableUncompressed.Length != (int)mFileTableLength) { * throw new Exception("Filesize missmatch! Uncompressed Body Size is not equal to Uncompressed Length!"); * } */ // Only read body? if (skipFiles == false) { for (int i = 0, offset = 0; i < fileCount; i++) { var filepath = string.Empty; char c; var itemTableOffset = (uint)offset; while ((c = (char)mFiletableUncompressed[offset++]) != '\0') { filepath += c; } filepath = Tools.UnifyPath(filepath); var item = new RoGrfFileItem { TableOffset = itemTableOffset, Index = Files.Count, Filepath = filepath, Flags = mFiletableUncompressed[offset + 12] }; // File or directory? if (item.IsFile) { item.LengthCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset); item.LengthCompressedAlign = BitConverter.ToUInt32(mFiletableUncompressed, offset + 4); item.LengthUnCompressed = BitConverter.ToUInt32(mFiletableUncompressed, offset + 8); // Offset is base offset + grf header item.DataOffset = BitConverter.ToUInt32(mFiletableUncompressed, offset + 13) + GrfHeaderLen; // from eAtehna, DES encryption item.Cycle = 1; switch (item.Flags) { case 3: for (var lop = 10; item.LengthCompressed >= lop; lop = lop * 10, item.Cycle++) { } break; case 5: item.Cycle = 0; break; default: item.Cycle = -1; break; } } else { // skip dirs offset += (int)GrfFileLen; continue; } // FIX: Some files in a tested grf are duplicated? // I cant remember grf version or something else.. if (GetFileByHash(item.NameHash) != null) { // Duplicate file, just skip it offset += (int)GrfFileLen; continue; } Files.Add(item.NameHash, item); mStringlist.Add(item.NameHash); mFileDataLength += item.LengthCompressedAlign; offset += (int)GrfFileLen; #if !DISABLE_GRF_EVENTS OnItemAdded(item, i, fileCount); #endif } } return(true); }
/// <summary> /// Caches the file data /// <para>Note: Updated files wont be recached!</para> /// <para>Only an empty Buffer will be created, if data is null</para> /// </summary> /// <param name="item">The grf file</param> public void CacheFileData(RoGrfFileItem item) { EnsureFilestream(); // Data from added or updated files if (item.IsAdded || item.IsUpdated) { item.FileData = File.ReadAllBytes(item.NewFilepath); return; } item.FileData = new byte[item.LengthCompressedAlign]; if (item.LengthCompressedAlign > 0) { // maybe its a Directory mFileStream.Seek(item.DataOffset, SeekOrigin.Begin); if ((mFileStream.Position + item.LengthCompressedAlign) >= mFileStream.Length) { throw new Exception("End of Stream reached - can not read Filedata from GRF!"); } mFileStream.Read(item.FileData, 0, (int)item.LengthCompressedAlign); } }
public object Clone() { var item = new RoGrfFileItem { Index = Index, Filepath = Filepath, LengthCompressed = LengthCompressed, LengthCompressedAlign = LengthCompressedAlign, LengthUnCompressed = LengthUnCompressed, Flags = Flags, DataOffset = DataOffset, Cycle = Cycle, State = State, NewFilepath = NewFilepath }; if (FileData != null) { item.FileData = FileData.Clone() as byte[]; } return item; }
/// <summary> /// Triggers the ItemWrite event. /// </summary> /// <param name="item"></param> public void OnItemWrite(RoGrfFileItem item) { if (ItemWrite == null) { return; } var p = (int)(((float)item.Index / Files.Count) * 100); if (p == mCurrentItemPercent) { return; } mCurrentItemPercent = p; ItemWrite(item, p); }
private void RemoveFile(RoGrfFileItem grfItem, int selectedIndex, bool refresh) { mGrfFile.DeleteFile(grfItem.NameHash); listView.RemoveIndizies( new List<int>( new[] { selectedIndex } ) ); grfItem = null; // Refresh info if (refresh) { SetGrfInfo(); } }