static bool PackFiles(string[] args) { // Parse parameters, validate. if (args[1].Length > 4) { Console.WriteLine("Creator id " + args[1] + " must be 4 chars or less."); return false; } string strCreatorId = args[1]; string strFullPathPdb = Path.GetFullPath(args[2]); string strFilePdb = Path.GetFileName(strFullPathPdb); string strDirPdb = Path.GetDirectoryName(strFullPathPdb); if (strDirPdb == "") strDirPdb = "."; if (strFilePdb.Length > 31) { Console.WriteLine("Pdb filename " + strFilePdb + " must be 31 characters or less."); return false; } string strFileSpec; if (args.Length == 3) { strFileSpec = ".\\*.*"; } else { strFileSpec = args[3]; } // Get list of files to add string strFileFileSpecAdd = Path.GetFileName(strFileSpec); string strDirFileSpecAdd = Path.GetDirectoryName(strFileSpec); if (strDirFileSpecAdd == "") strDirFileSpecAdd = "."; string[] astrFilesAdd = Directory.GetFiles(strDirFileSpecAdd, strFileFileSpecAdd); // File types not to compress ArrayList alsStrFilesNoCompress = new ArrayList(); if (args.Length > 4) { if (args[4] == "-nocompress") { for (int i = 5; i < args.Length; i++) { string[] astrFiles = Directory.GetFiles(strDirFileSpecAdd, args[i]); foreach (string str in astrFiles) alsStrFilesNoCompress.Add(Path.GetFullPath(str)); } } } // Print status Console.Write("Packing files... "); PdbPacker pdbp = new PdbPacker(); foreach (string strFileAdd in astrFilesAdd) { // Don't add the .pdb we're building string strFullPathAdd = Path.GetFullPath(strFileAdd); if (strFullPathPdb.ToLower() == strFullPathAdd.ToLower()) continue; // Get filename only, check length string strFile = Path.GetFileName(strFullPathAdd).ToLower(); if (strFile.Length >= s_cbFilenameMax) { Console.WriteLine("The file " + strFile + " is too long. Must be " + (s_cbFilenameMax - 1) + "chars max."); return false; } // Compress or not? bool fCompress = true; foreach (string strFileNoCompress in alsStrFilesNoCompress) { if (strFullPathAdd.ToLower() == strFileNoCompress.ToLower()) { fCompress = false; break; } } // Read the file Stream stm = new FileStream(strFullPathAdd, FileMode.Open, FileAccess.Read); BinaryReader brdr = new BinaryReader(stm); PdbPacker.File file = new PdbPacker.File(strFile, brdr.ReadBytes((int)brdr.BaseStream.Length), fCompress); brdr.Close(); pdbp.Add(file); } // Save out pdbp.Save(strFullPathPdb, strCreatorId); return true; }
static bool ViewFiles(string strFilePdb) { // Open pack pdb PdbPacker pdbp = new PdbPacker(strFilePdb); // For each file... for (int iFile = 0; iFile < pdbp.Count; iFile++) { PdbPacker.File file = pdbp[iFile]; int cbCompressed = file.GetCompressedSize(); int cbUncompressed = (int)file.ab.Length; int nPercentSavings = ((cbUncompressed - cbCompressed) * 100 + cbCompressed / 2) / cbCompressed; Console.WriteLine(file.str + ", " + cbUncompressed + " bytes, " + cbCompressed + " bytes compressed, " + nPercentSavings + "% savings"); } return true; }
static bool UnpackFiles(string strFilePdb) { // Open pack pdb PdbPacker pdbp = new PdbPacker(strFilePdb); // For each file... for (int iFile = 0; iFile < pdbp.Count; iFile++) { PdbPacker.File file = pdbp[iFile]; BinaryWriter bwtr = new BinaryWriter(new FileStream(file.str, FileMode.Create, FileAccess.Write, FileShare.None)); bwtr.Write(file.ab); bwtr.Close(); Console.WriteLine("Wrote " + file.str + ", " + file.ab.Length + " bytes."); } return true; }
public static void SaveExpansionPdb(string strFile, Document[] adoc, string strVersion) { // First save all level docs //annoying //DocManager.SaveAllModified(typeof(LevelDoc)); // Remember active document LevelDoc lvldActive = (LevelDoc)DocManager.GetActiveDocument(typeof(LevelDoc)); // Save documents adoc in an expansion .pdb. Expansion .pdbs need: // - .lvl, .tmap, .trmap, but not .tsets since these come from game .pdbs // - need a version.txt // - need an if demo trigger check "inserted" at save time // - .pdb needs WARI creator, ADD1 type // - data should be compressed for obfuscation purposes PdbPacker pdbp = new PdbPacker(); // Add version.txt byte[] abT = new byte[strVersion.Length + 1]; for (int n = 0; n < strVersion.Length; n++) abT[n] = (byte)strVersion[n]; abT[abT.Length - 1] = 0; pdbp.Add(new PdbPacker.File("version.txt", abT)); // Load res.h from embedded resource in prep for pre-process System.Reflection.Assembly ass = typeof(GobImage).Module.Assembly; Stream stmResDotH = ass.GetManifestResourceStream("m.EmbeddedResources." + "res.h"); if (stmResDotH == null) throw new Exception("Cannot load res.h"); // Compile levels Random rand = new Random(); ArrayList alsTileSets = new ArrayList(); foreach (LevelDoc lvld in adoc) { // Need to do this unfortunately; some of the "saving" code relies on what the "active" document // is!! DocManager.SetActiveDocument(typeof(LevelDoc), lvld); TemplateDoc tmpd = lvld.GetTemplateDoc(); // Get appropriate TileSet, or make one if this map // uses a new tile collection TileSet tset = null; foreach (TileSet tsetT in alsTileSets) { if (tsetT.TemplateDoc == tmpd) { tset = tsetT; break; } } // Create new tile set if none found if (tset == null) { tset = new TileSet(tmpd, tmpd.GetName() + ".tset"); alsTileSets.Add(tset); } #if false // Generate base file name for this level (this is never user-visible, but it should be // as unique as possible char[] achBase = new char[16]; for (int n = 0; n < achBase.Length; n++) { int nT = rand.Next() % (26 + 10); if (nT < 26) { achBase[n] = (char)(nT + 97); } else { achBase[n] = (char)(nT + 48 - 26); } } if (lvld.MaxPlayers > 1) { achBase[0] = 'm'; achBase[1] = '_'; } string strBase = new String(achBase); #else // This isn't unique which can cause problems due to how packfiles work. // Could change packfile api to accept .pdb parameter. // Note1: set next mission action requires predictable filename // Note2: mission sorting is based on filename, not title // Could put lots of "support" in to fix these problems, or just ship // it like this. // // Hack: filename length 29 // Maximum extension on filename: 7 string strBase = lvld.Title; if (strBase.Length > 29 - 7) strBase = strBase.Substring(0, 29 - 7); // If multiplayer, add "m_" to the name by losing the last two characters // so sort order is preserved if (lvld.MaxPlayers > 1) strBase = "m_" + strBase.Substring(0, strBase.Length - 2); #endif // Get tile map file for this level MemoryStream stmTmap = new MemoryStream(); TileMap tmap = TileMap.CreateFromImage(tset, lvld.GetMapBitmap(tmpd.TileSize, tmpd, true), tmpd.TileSize); tmap.Save(stmTmap); string strTmap = strBase + ".tmap"; pdbp.Add(new PdbPacker.File(strTmap, stmTmap.ToArray())); stmTmap.Close(); // Get the terrain map file for this level MemoryStream stmTRmap = new MemoryStream(); TerrainMap trmap = new TerrainMap(lvld.GetTerrainMap(tmpd.TileSize, tmpd, false)); trmap.Save(stmTRmap); string strTRmap = strBase + ".trmap"; pdbp.Add(new PdbPacker.File(strTRmap, stmTRmap.ToArray())); stmTRmap.Close(); // Save .ini file for this level doc MemoryStream stmLvld = new MemoryStream(); lvld.SaveIni(stmLvld, -1, strTmap, strTRmap, tmpd.GetName() + ".palbin", true); // Pre-process stmLvld.Seek(0, SeekOrigin.Begin); MemoryStream stmPreprocessed = Misc.PreprocessStream(stmLvld, stmResDotH); stmPreprocessed.Seek(0, SeekOrigin.Begin); Ini iniPreProcessed = new Ini(stmPreprocessed); MemoryStream stmLvldPreProcessedBinary = new MemoryStream(); iniPreProcessed.SaveBinary(stmLvldPreProcessedBinary); stmLvldPreProcessedBinary.Close(); string strLvlName = lvld.OutputFilename; if (strLvlName == null) { strLvlName = strBase + ".lvl"; } pdbp.Add(new PdbPacker.File(strLvlName, stmLvldPreProcessedBinary.ToArray())); stmLvldPreProcessedBinary.Close(); } stmResDotH.Close(); // Restore active document if (lvldActive != null) DocManager.SetActiveDocument(typeof(LevelDoc), lvldActive); // Now save out pdb pdbp.Save(strFile, "WARI", "ADD2"); }
public static void ImportExpansionPdb(string strFile) { PdbPacker pdbp = new PdbPacker(strFile); ArrayList alsTileSets = new ArrayList(); for (int i = 0; i < pdbp.Count; i++) { PdbPacker.File file = pdbp[i]; if (!file.str.EndsWith(".lvl")) { continue; } // Load up the pieces Ini ini = Ini.LoadBinary(new MemoryStream(file.ab)); string strTileMapFilename = ini["General"]["TileMap"].Value; TileMap tmap = TileMap.Load(new MemoryStream(pdbp[strTileMapFilename].ab)); // First, tell the active LevelDoc not to switch its templates based on the following // template load LevelDoc lvldActive = (LevelDoc)DocManager.GetActiveDocument(typeof(LevelDoc)); if (lvldActive != null) { lvldActive.SwitchTemplatesEnabled = false; } // If the TileSet for this level is not yet available, load it now TemplateDoc tmpd = (TemplateDoc)DocManager.OpenDocument(tmap.Filename.Replace(".tset", ".tc")); TileSet tset = null; foreach (TileSet tsetT in alsTileSets) { if (tsetT.FileName == tmap.Filename) { tset = tsetT; break; } } if (tset == null) { tset = new TileSet(tmpd, tmap.Filename); alsTileSets.Add(tset); } // Re-enable template switching if (lvldActive != null) { lvldActive.SwitchTemplatesEnabled = true; } // Create a new level description, and deduce which templates are in it, with what visibility LevelDoc lvld = (LevelDoc)DocManager.NewDocument(typeof(LevelDoc), null); lvld.OutputFilename = file.str; ImportTileMap(tmap, tset, tmpd, lvld); // Walls are stored in the terrain map. Load them. string strTrmapFilename = ini["General"]["TerrainMap"].Value; TerrainMap trmap = TerrainMap.Load(new MemoryStream(pdbp[strTrmapFilename].ab)); ImportWalls(trmap, lvld); // Load everything else lvld.LoadIni(ini); } }
void SavePdb(string strPdbFile) { // Make a list of unique sound files PdbPacker pdbp = new PdbPacker(); int cSfx = m_alsNames.Count; StringCollection strcUniqueSounds = new StringCollection(); ArrayList alsPcm = new ArrayList(); for (int iSfx = 0; iSfx < cSfx; iSfx++) { if (!listViewSfx.Items[iSfx].Checked) continue; if (!(bool)m_alsSfxEnabled[iSfx]) continue; string strFile = listViewSfx.Items[iSfx].SubItems[1].Text; if (strFile == null) continue; strFile.Trim(); if (strFile.Length == 0) continue; int istr = strcUniqueSounds.IndexOf(strFile); if (istr == -1) istr = strcUniqueSounds.Add(strFile); } // Serialize names out ArrayList alsStringOffsets = new ArrayList(); BinaryWriter bwtr = new BinaryWriter(new MemoryStream()); bwtr.Write(Misc.SwapUShort((ushort)strcUniqueSounds.Count)); for (int iSound = 0; iSound < strcUniqueSounds.Count; iSound++) { alsStringOffsets.Add(bwtr.BaseStream.Position); string strFile = Path.ChangeExtension(strcUniqueSounds[iSound], ".snd"); char[] sz = strFile.ToCharArray(); bwtr.Write(sz); bwtr.Write((byte)0); } byte[] abSoundFiles = new byte[bwtr.BaseStream.Length]; bwtr.BaseStream.Seek(0, SeekOrigin.Begin); bwtr.BaseStream.Read(abSoundFiles, 0, (int)bwtr.BaseStream.Length); bwtr.Close(); // soundfiles file PdbPacker.File fileSounds = new PdbPacker.File("soundfiles", abSoundFiles); pdbp.Add(fileSounds); // Now serialize the sfx entries in the order of the names bwtr = new BinaryWriter(new MemoryStream()); for (int iName = 0; iName < m_alsNames.Count; iName++) { // Need to find the entry in listViewSfx for this name since the persist // order needs to match soundeffects.h. string strName = ((StringCollection)m_alsNames[iName])[0]; int iSfx; bool fFound = false; for (iSfx = 0; iSfx < cSfx; iSfx++) { if (strName == listViewSfx.Items[iSfx].SubItems[0].Text) { fFound = true; break; } } if (!fFound) throw new Exception("Internal error"); string strFile = listViewSfx.Items[iSfx].SubItems[1].Text; if (!listViewSfx.Items[iSfx].Checked) strFile = null; if (!(bool)m_alsSfxEnabled[iSfx]) strFile = null; if (strFile == null) { bwtr.Write((byte)0xff); } else { strFile.Trim(); if (strFile.Length == 0) { bwtr.Write((byte)0xff); } else { bwtr.Write((byte)strcUniqueSounds.IndexOf(strFile)); } } bwtr.Write((byte)0); // bwtr.Write(byte.Parse(listViewSfx.Items[iSfx].SubItems[2].Text)); int nPriority = m_strcPriorities.IndexOf(listViewSfx.Items[iSfx].SubItems[3].Text); if (nPriority < 0) { MessageBox.Show("Warning: " + listViewSfx.Items[iSfx].SubItems[0].Text + " has an unfamiliar priority."); } bwtr.Write((byte)nPriority); } byte[] abSfxEntries = new byte[bwtr.BaseStream.Length]; bwtr.BaseStream.Seek(0, SeekOrigin.Begin); bwtr.BaseStream.Read(abSfxEntries, 0, (int)bwtr.BaseStream.Length); bwtr.Close(); PdbPacker.File fileSfxEntries = new PdbPacker.File("SfxEntries", abSfxEntries); pdbp.Add(fileSfxEntries); // Now add in all the sounds for (int istrFile = 0; istrFile < strcUniqueSounds.Count; istrFile++) { string strFile = Path.GetFullPath(textBoxSoundsDir.Text) + "\\" + strcUniqueSounds[istrFile]; Pcm pcm = new Pcm(strFile); PdbPacker.File fileT = new PdbPacker.File(); fileT.str = Path.ChangeExtension(strcUniqueSounds[istrFile], ".snd"); fileT.ab = pcm.GetSndEncoding(); fileT.fCompress = false; pdbp.Add(fileT); } // Ready to save pdb pdbp.Save(strPdbFile, "WARI"); }