Beispiel #1
0
        public override void Write(Stream destination)
        {
            string GetToolVersion()
            {
                AssemblyName assemblyName = Assembly.GetEntryAssembly().GetName();

                return($"{assemblyName.Name}, {assemblyName.Version.ToString()}");
            }

            DataPool vldPool = new DataPool(Align, 2048);

            vldPool.ProgressChanged += OnProgressChanged;

            using (CriCpkSection cpkSection = new CriCpkSection(destination, "CPK ", enableMask))
            {
                cpkSection.Writer.WriteStartTable("CpkHeader");

                cpkSection.Writer.WriteField("UpdateDateTime", typeof(ulong));
                cpkSection.Writer.WriteField("FileSize", typeof(ulong));
                cpkSection.Writer.WriteField("ContentOffset", typeof(ulong));
                cpkSection.Writer.WriteField("ContentSize", typeof(ulong));

                if (mode == CriCpkMode.FileName || mode == CriCpkMode.FileNameAndId)
                {
                    cpkSection.Writer.WriteField("TocOffset", typeof(ulong));
                    cpkSection.Writer.WriteField("TocSize", typeof(ulong));
                    cpkSection.Writer.WriteField("TocCrc", typeof(uint), null);
                    cpkSection.Writer.WriteField("EtocOffset", typeof(ulong));
                    cpkSection.Writer.WriteField("EtocSize", typeof(ulong));
                }

                else
                {
                    cpkSection.Writer.WriteField("TocOffset", typeof(ulong), null);
                    cpkSection.Writer.WriteField("TocSize", typeof(ulong), null);
                    cpkSection.Writer.WriteField("TocCrc", typeof(uint), null);
                    cpkSection.Writer.WriteField("EtocOffset", typeof(ulong), null);
                    cpkSection.Writer.WriteField("EtocSize", typeof(ulong), null);
                }

                if (mode == CriCpkMode.Id || mode == CriCpkMode.FileNameAndId)
                {
                    cpkSection.Writer.WriteField("ItocOffset", typeof(ulong));
                    cpkSection.Writer.WriteField("ItocSize", typeof(ulong));
                    cpkSection.Writer.WriteField("ItocCrc", typeof(uint), null);
                }

                else
                {
                    cpkSection.Writer.WriteField("ItocOffset", typeof(ulong), null);
                    cpkSection.Writer.WriteField("ItocSize", typeof(ulong), null);
                    cpkSection.Writer.WriteField("ItocCrc", typeof(uint), null);
                }

                cpkSection.Writer.WriteField("GtocOffset", typeof(ulong), null);
                cpkSection.Writer.WriteField("GtocSize", typeof(ulong), null);
                cpkSection.Writer.WriteField("GtocCrc", typeof(uint), null);

                cpkSection.Writer.WriteField("EnabledPackedSize", typeof(ulong));
                cpkSection.Writer.WriteField("EnabledDataSize", typeof(ulong));
                cpkSection.Writer.WriteField("TotalDataSize", typeof(ulong), null);

                cpkSection.Writer.WriteField("Tocs", typeof(uint), null);
                cpkSection.Writer.WriteField("Files", typeof(uint));
                cpkSection.Writer.WriteField("Groups", typeof(uint));
                cpkSection.Writer.WriteField("Attrs", typeof(uint));
                cpkSection.Writer.WriteField("TotalFiles", typeof(uint), null);
                cpkSection.Writer.WriteField("Directories", typeof(uint), null);
                cpkSection.Writer.WriteField("Updates", typeof(uint), null);

                cpkSection.Writer.WriteField("Version", typeof(ushort));
                cpkSection.Writer.WriteField("Revision", typeof(ushort));
                cpkSection.Writer.WriteField("Align", typeof(ushort));
                cpkSection.Writer.WriteField("Sorted", typeof(ushort));
                cpkSection.Writer.WriteField("EID", typeof(ushort), null);

                cpkSection.Writer.WriteField("CpkMode", typeof(uint));
                cpkSection.Writer.WriteField("Tvers", typeof(string));

                if (!string.IsNullOrEmpty(Comment))
                {
                    cpkSection.Writer.WriteField("Comment", typeof(string));
                }

                else
                {
                    cpkSection.Writer.WriteField("Comment", typeof(string), null);
                }

                cpkSection.Writer.WriteField("Codec", typeof(uint));
                cpkSection.Writer.WriteField("DpkItoc", typeof(uint));

                MemoryStream tocMemoryStream  = null;
                MemoryStream itocMemoryStream = null;
                MemoryStream etocMemoryStream = null;

                if (mode == CriCpkMode.FileName || mode == CriCpkMode.FileNameAndId)
                {
                    tocMemoryStream  = new MemoryStream();
                    etocMemoryStream = new MemoryStream();

                    var orderedEntries = entries.OrderBy(entry => entry.Name).ToList();

                    using (CriCpkSection tocSection = new CriCpkSection(tocMemoryStream, "TOC ", enableMask))
                        using (CriCpkSection etocSection = new CriCpkSection(etocMemoryStream, "ETOC", enableMask))
                        {
                            tocSection.Writer.WriteStartTable("CpkTocInfo");

                            tocSection.Writer.WriteField("DirName", typeof(string));
                            tocSection.Writer.WriteField("FileName", typeof(string));
                            tocSection.Writer.WriteField("FileSize", typeof(uint));
                            tocSection.Writer.WriteField("ExtractSize", typeof(uint));
                            tocSection.Writer.WriteField("FileOffset", typeof(ulong));
                            tocSection.Writer.WriteField("ID", typeof(uint));
                            tocSection.Writer.WriteField("UserString", typeof(string));

                            etocSection.Writer.WriteStartTable("CpkEtocInfo");

                            etocSection.Writer.WriteField("UpdateDateTime", typeof(ulong));
                            etocSection.Writer.WriteField("LocalDir", typeof(string));

                            foreach (CriCpkEntry entry in orderedEntries)
                            {
                                tocSection.Writer.WriteRow(true,
                                                           (entry.DirectoryName).Replace('\\', '/'),
                                                           entry.Name,
                                                           (uint)entry.Length,
                                                           (uint)entry.Length,
                                                           (ulong)(vldPool.Length - 2048),
                                                           entry.Id,
                                                           entry.Comment);

                                etocSection.Writer.WriteRow(true,
                                                            CpkDateTimeFromDateTime(entry.UpdateDateTime),
                                                            entry.DirectoryName);

                                vldPool.Put(entry.FilePath);
                            }

                            tocSection.Writer.WriteEndTable();
                            etocSection.Writer.WriteEndTable();
                        }

                    if (mode == CriCpkMode.FileNameAndId)
                    {
                        itocMemoryStream = new MemoryStream();

                        using (CriCpkSection itocSection = new CriCpkSection(itocMemoryStream, "ITOC", enableMask))
                        {
                            itocSection.Writer.WriteStartTable("CpkExtendId");

                            itocSection.Writer.WriteField("ID", typeof(int));
                            itocSection.Writer.WriteField("TocIndex", typeof(int));

                            foreach (CriCpkEntry entry in orderedEntries)
                            {
                                itocSection.Writer.WriteRow(true,
                                                            (int)entry.Id,
                                                            orderedEntries.IndexOf(entry));
                            }

                            itocSection.Writer.WriteEndTable();
                        }
                    }
                }

                else if (mode == CriCpkMode.Id)
                {
                    itocMemoryStream = new MemoryStream();

                    using (CriCpkSection itocSection = new CriCpkSection(itocMemoryStream, "ITOC", enableMask))
                    {
                        itocSection.Writer.WriteStartTable("CpkItocInfo");

                        itocSection.Writer.WriteField("FilesL", typeof(uint));
                        itocSection.Writer.WriteField("FilesH", typeof(uint));
                        itocSection.Writer.WriteField("DataL", typeof(byte[]));
                        itocSection.Writer.WriteField("DataH", typeof(byte[]));

                        List <CriCpkEntry> filesL = entries.Where(entry => entry.Length < ushort.MaxValue).ToList();
                        List <CriCpkEntry> filesH = entries.Where(entry => entry.Length > ushort.MaxValue).ToList();

                        itocSection.Writer.WriteStartRow();

                        using (MemoryStream dataMemoryStream = new MemoryStream())
                            using (CriTableWriter dataWriter = CriTableWriter.Create(dataMemoryStream))
                            {
                                dataWriter.WriteStartTable("CpkItocL");

                                dataWriter.WriteField("ID", typeof(ushort));
                                dataWriter.WriteField("FileSize", typeof(ushort));
                                dataWriter.WriteField("ExtractSize", typeof(ushort));

                                foreach (CriCpkEntry entry in filesL)
                                {
                                    dataWriter.WriteRow(true,
                                                        (ushort)entry.Id,
                                                        (ushort)entry.Length,
                                                        (ushort)entry.Length);
                                }

                                dataWriter.WriteEndTable();

                                itocSection.Writer.WriteValue("DataL", dataMemoryStream.ToArray());
                            }

                        using (MemoryStream dataMemoryStream = new MemoryStream())
                            using (CriTableWriter dataWriter = CriTableWriter.Create(dataMemoryStream))
                            {
                                dataWriter.WriteStartTable("CpkItocH");

                                dataWriter.WriteField("ID", typeof(ushort));
                                dataWriter.WriteField("FileSize", typeof(uint));
                                dataWriter.WriteField("ExtractSize", typeof(uint));

                                foreach (CriCpkEntry entry in filesH)
                                {
                                    dataWriter.WriteRow(true,
                                                        (ushort)entry.Id,
                                                        (uint)entry.Length,
                                                        (uint)entry.Length);
                                }

                                dataWriter.WriteEndTable();

                                itocSection.Writer.WriteValue("DataH", dataMemoryStream.ToArray());
                            }

                        itocSection.Writer.WriteValue("FilesL", (uint)filesL.Count);
                        itocSection.Writer.WriteValue("FilesH", (uint)filesH.Count);
                        itocSection.Writer.WriteEndRow();
                        itocSection.Writer.WriteEndTable();
                    }

                    foreach (CriCpkEntry entry in entries.OrderBy(entry => entry.Id))
                    {
                        vldPool.Put(entry.FilePath);
                    }
                }

                else
                {
                    throw new NotImplementedException($"Unimplemented CPK mode ({mode})");
                }

                cpkSection.Writer.WriteStartRow();
                cpkSection.Writer.WriteValue("UpdateDateTime", CpkDateTimeFromDateTime(DateTime.Now));

                cpkSection.Writer.WriteValue("ContentOffset", (ulong)2048);
                cpkSection.Writer.WriteValue("ContentSize", (ulong)(vldPool.Length - 2048));

                if (tocMemoryStream != null)
                {
                    cpkSection.Writer.WriteValue("TocOffset", (ulong)vldPool.Put(tocMemoryStream));
                    cpkSection.Writer.WriteValue("TocSize", (ulong)tocMemoryStream.Length);
                }

                if (itocMemoryStream != null)
                {
                    cpkSection.Writer.WriteValue("ItocOffset", (ulong)vldPool.Put(itocMemoryStream));
                    cpkSection.Writer.WriteValue("ItocSize", (ulong)itocMemoryStream.Length);
                }

                if (etocMemoryStream != null)
                {
                    cpkSection.Writer.WriteValue("EtocOffset", (ulong)vldPool.Put(etocMemoryStream));
                    cpkSection.Writer.WriteValue("EtocSize", (ulong)etocMemoryStream.Length);
                }

                long totalDataSize = 0;
                foreach (CriCpkEntry entry in entries)
                {
                    totalDataSize += entry.Length;
                }

                cpkSection.Writer.WriteValue("EnabledPackedSize", totalDataSize);
                cpkSection.Writer.WriteValue("EnabledDataSize", totalDataSize);

                cpkSection.Writer.WriteValue("Files", (uint)entries.Count);

                cpkSection.Writer.WriteValue("Version", (ushort)7);
                cpkSection.Writer.WriteValue("Revision", (ushort)2);
                cpkSection.Writer.WriteValue("Align", Align);
                cpkSection.Writer.WriteValue("Sorted", (ushort)1);

                cpkSection.Writer.WriteValue("CpkMode", (uint)mode);
                cpkSection.Writer.WriteValue("Tvers", GetToolVersion());
                cpkSection.Writer.WriteValue("Comment", Comment);

                cpkSection.Writer.WriteValue("FileSize", (ulong)vldPool.Length);

                cpkSection.Writer.WriteEndRow();
                cpkSection.Writer.WriteEndTable();
            }

            DataStream.Pad(destination, 2042);
            DataStream.WriteCString(destination, "(c)CRI", 6);

            vldPool.Write(destination);
        }
Beispiel #2
0
        public override void Read(Stream source)
        {
            using (CriTableReader reader = CriCpkSection.Open(source, source.Position, "CPK "))
            {
                reader.Read();

                bool isLatestVersion = reader.ContainsField("CpkMode");

                if (isLatestVersion)
                {
                    mode = (CriCpkMode)reader.GetUInt32("CpkMode");
                }

                else
                {
                    bool tocEnabled  = reader.GetUInt64("TocOffset") > 0;
                    bool itocEnabled = reader.GetUInt64("ItocOffset") > 0;

                    if (tocEnabled && !itocEnabled)
                    {
                        mode = CriCpkMode.FileName;
                    }

                    else if (!tocEnabled && itocEnabled)
                    {
                        mode = CriCpkMode.Id;
                    }

                    else if (tocEnabled && itocEnabled)
                    {
                        mode = CriCpkMode.FileNameAndId;
                    }

                    else
                    {
                        mode = CriCpkMode.None;
                    }
                }

                // No need to waste time, stop right there.
                if (mode == CriCpkMode.None)
                {
                    return;
                }

                long tocPosition     = (long)reader.GetUInt64("TocOffset");
                long itocPosition    = (long)reader.GetUInt64("ItocOffset");
                long etocPosition    = (long)reader.GetUInt64("EtocOffset");
                long contentPosition = (long)reader.GetUInt64("ContentOffset");

                align = reader.GetUInt16("Align");

                if (mode == CriCpkMode.FileName || mode == CriCpkMode.FileNameAndId)
                {
                    using (CriTableReader tocReader = CriCpkSection.Open(source, tocPosition, "TOC "))
                        using (CriTableReader etocReader = CriCpkSection.Open(source, etocPosition, "ETOC"))
                        {
                            while (tocReader.Read())
                            {
                                CriCpkEntry entry = new CriCpkEntry();
                                entry.DirectoryName      = tocReader.GetString("DirName");
                                entry.Name               = tocReader.GetString("FileName");
                                entry.Length             = tocReader.GetUInt32("FileSize");
                                entry.Position           = (long)tocReader.GetUInt64("FileOffset");
                                entry.Id                 = isLatestVersion ? tocReader.GetUInt32("ID") : tocReader.GetUInt32("Info");
                                entry.Comment            = tocReader.GetString("UserString");
                                entry.UncompressedLength = tocReader.GetUInt32("ExtractSize");
                                entry.IsCompressed       = entry.Length != entry.UncompressedLength;

                                if (contentPosition < tocPosition)
                                {
                                    entry.Position += contentPosition;
                                }

                                else
                                {
                                    entry.Position += tocPosition;
                                }

                                entry.Position = Helpers.Align(entry.Position, align);

                                etocReader.MoveToRow(tocReader.CurrentRow);
                                entry.UpdateDateTime = DateTimeFromCpkDateTime(etocReader.GetUInt64("UpdateDateTime"));

                                entries.Add(entry);
                            }
                        }

                    if (mode == CriCpkMode.FileNameAndId && isLatestVersion)
                    {
                        using (CriTableReader itocReader = CriCpkSection.Open(source, itocPosition, "ITOC"))
                        {
                            while (itocReader.Read())
                            {
                                entries[itocReader.GetInt32("TocIndex")].Id = (uint)itocReader.GetInt32("ID");
                            }
                        }
                    }
                }

                else if (mode == CriCpkMode.Id)
                {
                    using (CriTableReader itocReader = CriCpkSection.Open(source, itocPosition, "ITOC"))
                    {
                        while (itocReader.Read())
                        {
                            if (itocReader.GetUInt32("FilesL") > 0)
                            {
                                using (CriTableReader dataReader = itocReader.GetTableReader("DataL"))
                                {
                                    while (dataReader.Read())
                                    {
                                        CriCpkEntry entry = new CriCpkEntry();
                                        entry.Id                 = dataReader.GetUInt16("ID");
                                        entry.Length             = dataReader.GetUInt16("FileSize");
                                        entry.UncompressedLength = dataReader.GetUInt16("ExtractSize");
                                        entry.IsCompressed       = entry.Length != entry.UncompressedLength;

                                        entries.Add(entry);
                                    }
                                }
                            }

                            if (itocReader.GetUInt32("FilesH") > 0)
                            {
                                using (CriTableReader dataReader = itocReader.GetTableReader("DataH"))
                                {
                                    while (dataReader.Read())
                                    {
                                        CriCpkEntry entry = new CriCpkEntry();
                                        entry.Id                 = dataReader.GetUInt16("ID");
                                        entry.Length             = dataReader.GetUInt32("FileSize");
                                        entry.UncompressedLength = dataReader.GetUInt32("ExtractSize");
                                        entry.IsCompressed       = entry.Length != entry.UncompressedLength;

                                        entries.Add(entry);
                                    }
                                }
                            }
                        }
                    }

                    long entryPosition = contentPosition;
                    foreach (CriCpkEntry entry in entries.OrderBy(entry => entry.Id))
                    {
                        entryPosition = Helpers.Align(entryPosition, align);

                        entry.Position = entryPosition;
                        entryPosition += entry.Length;
                    }
                }

                else
                {
                    throw new NotImplementedException($"Unimplemented CPK mode ({mode})");
                }

                Comment = reader.GetString("Comment");
            }
        }