コード例 #1
0
        private static bool ApplyDefaultMotionMetadata(PSB psb, PsbDictionary metadata)
        {
            List <(string Chara, string Motion)> knownMotions = new List <(string Chara, string Motion)>
            {
                ("body_parts", "全身変形基礎"),
                ("body_parts", "下半身変形基礎"),
                ("head_parts", "頭部変形基礎"),
                ("head_parts", "頭部全体変形"),
                ("all_parts", "タイムライン構造"),
                ("all_parts", "全体構造")
            };

            //Find a known pattern
            foreach (var knownMotion in knownMotions)
            {
                if (psb.Objects.FindByPath($"/object/{knownMotion.Chara}") is PsbDictionary knownDic && knownDic["motion"].Children(knownMotion.Motion) is PsbDictionary motionDic && motionDic.Count > 0)
                {
                    metadata["chara"]  = knownMotion.Chara.ToPsbString();
                    metadata["motion"] = knownMotion.Motion.ToPsbString();
                    return(true);
                }
            }

            return(false);
        }
コード例 #2
0
        public bool TryGetArchData(PSB psb, PsbDictionary dic, out IArchData data)
        {
            data = null;
            //if (psb.Platform != PsbSpec.nx)
            //{
            //    return false;
            //}
            if (dic.Count != 1 || !(dic["archData"] is PsbDictionary archDic))
            {
                return(false);
            }

            if (archDic["body"] is PsbDictionary body &&
                body["data"] is PsbResource aData && body["sampleCount"] is PsbNumber sampleCount &&
                archDic["ext"] is PsbString ext && ext.Value == Extensions[0] &&
                archDic["samprate"] is PsbNumber sampRate)
            {
                data = new OpusArchData
                {
                    Data        = aData,
                    SampRate    = sampRate.IntValue,
                    SampleCount = sampleCount.IntValue
                };

                return(true);
            }

            return(false);
        }
コード例 #3
0
        /// <summary>
        /// Get name
        /// </summary>
        /// <param name="c"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static string GetName(this IPsbSingleton c, PsbDictionary parent = null)
        {
            var source = parent ?? c?.Parents.FirstOrDefault(p => p is PsbDictionary) as PsbDictionary;
            var result = source?.FirstOrDefault(pair => Equals(pair.Value, c));

            return(result?.Value == null ? null : result.Value.Key);
        }
コード例 #4
0
ファイル: PsbResCollector.cs プロジェクト: jszhtian/FreeMote
        public static IPsbValue FindByPath(this PsbDictionary psbObj, string path)
        {
            if (psbObj == null)
            {
                return(null);
            }
            if (path.StartsWith("/"))
            {
                path = new string(path.SkipWhile(c => c == '/').ToArray());
            }

            if (path.Contains("/"))
            {
                var pos     = path.IndexOf('/');
                var current = path.Substring(0, pos);
                if (pos == path.Length - 1)
                {
                    return(psbObj[current]);
                }
                var currentObj = psbObj[current];
                if (currentObj is PsbDictionary collection)
                {
                    path = path.Substring(pos);
                    return(collection.FindByPath(path));
                }
            }
            return(psbObj[path]);
        }
コード例 #5
0
ファイル: SoundArchiveType.cs プロジェクト: RadioJah/FreeMote
        internal AudioMetadata GenerateAudioMetadata(PSB psb, string name, PsbDictionary voice, FreeMountContext context)
        {
            var md = new AudioMetadata();

            md.Name = name;

            if (voice["file"] is PsbString fileStr)
            {
                md.FileString = fileStr;
            }

            if (voice["loopStr"] is PsbString loopStr)
            {
                md.LoopStr = loopStr;
            }

            if (voice["loop"] is PsbNumber loopNum)
            {
                md.Loop = loopNum.IntValue;
            }

            if (voice["quality"] is PsbNumber qualityNum)
            {
                md.Quality = qualityNum.IntValue;
            }

            if (voice["type"] is PsbNumber typeNum)
            {
                md.Type = typeNum.IntValue;
            }

            if (voice["device"] is PsbNumber deviceNum)
            {
                md.Device = deviceNum.IntValue;
            }

            if (voice["channelList"] is PsbList channelList)
            {
                foreach (var channel in channelList)
                {
                    if (channel is PsbDictionary channelDic)
                    {
                        if (context.TryGetArchData(psb, channelDic, out var archData))
                        {
                            archData.PsbArchData = channelDic;
                            md.ChannelList.Add(archData);
                        }
                    }
                }
            }

            return(md);
        }
コード例 #6
0
        public static Dictionary <string, Bitmap> SplitTexture(PsbDictionary tex, PsbSpec spec)
        {
            var icon    = (PsbDictionary)tex["icon"];
            var texture = (PsbDictionary)tex["texture"];

            //var mipmap = (PsbDictionary)texture["mipMap"]; //TODO: Mipmap?
            Dictionary <string, Bitmap> textures = new Dictionary <string, Bitmap>(icon.Count);

            var pixel = texture[Consts.ResourceKey];

            if (pixel == null || !(pixel is PsbResource pixelRes))
            {
                throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                "External Texture PSB is not supported. Please Link textures into PSB.");
                return(textures);
            }

            var md = PsbResHelper.GenerateImageMetadata(texture, pixelRes);

            md.Spec = spec; //Important
            Bitmap bmp = md.ToImage();

            foreach (var iconPair in icon)
            {
                var    info   = (PsbDictionary)iconPair.Value;
                var    width  = (int)(PsbNumber)info["width"];
                var    height = (int)(PsbNumber)info["height"];
                var    top    = (int)(PsbNumber)info["top"];
                var    left   = (int)(PsbNumber)info["left"];
                Bitmap b      = new Bitmap(width, height, PixelFormat.Format32bppArgb);
#if USE_FASTBITMAP
                using (FastBitmap f = b.FastLock())
                {
                    f.CopyRegion(bmp, new Rectangle(left, top, width, height), new Rectangle(0, 0, b.Width, b.Height));
                }
#else
                Graphics g = Graphics.FromImage(b);
                //g.InterpolationMode = InterpolationMode.NearestNeighbor;
                //g.PixelOffsetMode = PixelOffsetMode.Half;
                g.DrawImage(bmp, new Rectangle(0, 0, b.Width, b.Height), new Rectangle(left, top, width, height),
                            GraphicsUnit.Pixel);
                g.Dispose();
#endif
                textures.Add(iconPair.Key, b);
            }

            bmp.Dispose();
            return(textures);
        }
コード例 #7
0
        public bool TryGetArchData(PSB psb, PsbDictionary dic, out IArchData data)
        {
            data = null;
            if (psb.Platform == PsbSpec.ps4 || psb.Platform == PsbSpec.vita)
            {
                if (dic.Count == 1 && dic["archData"] is PsbResource res)
                {
                    data = new Atrac9ArchData
                    {
                        Data = res
                    };

                    return(true);
                }

                return(false);
            }

            return(false);
        }
コード例 #8
0
        private static ResourceMetadata GenerateTachieResMetadata(PsbDictionary d, PsbResource r, string label = "")
        {
            int width = 1, height = 1;
            int top = 0, left = 0;
            var dd = d.Parent as PsbDictionary ?? d;

            if ((d["width"] ?? d["truncated_width"] ?? dd["width"]) is PsbNumber nw)
            {
                width = (int)nw;
            }

            if ((d["height"] ?? d["truncated_height"] ?? dd["height"]) is PsbNumber nh)
            {
                height = (int)nh;
            }

            if ((dd["top"] ?? d["top"]) is PsbNumber nx)
            {
                top = nx.AsInt;
            }

            if ((dd["left"] ?? d["left"]) is PsbNumber ny)
            {
                left = ny.AsInt;
            }

            var md = new ResourceMetadata()
            {
                Top        = top,
                Left       = left,
                TypeString = d["type"] as PsbString,
                Width      = width,
                Height     = height,
                Name       = r.Index.ToString(),
                Part       = label,
                Resource   = r,
            };

            return(md);
        }
コード例 #9
0
        public void TestGraft2()
        {
            var resPath  = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var pathGood = Path.Combine(resPath, "goodstr.freemote.psb");
            var pathBad  = Path.Combine(resPath, "goodStr.psb");

            var psbGood = new PSB(pathGood);
            var psbBad  = new PSB(pathBad);

            dynamic texGood = (PsbDictionary)psbGood.Objects["source"].Children("tex");
            dynamic texBad  = (PsbDictionary)psbBad.Objects["source"].Children("tex#000");
            var     badIcon = texBad["icon"];

            PsbDictionary newIcon = new PsbDictionary();

            foreach (var part in texGood["icon"])
            {
                var content = part.Value;
                var bi      = ((PsbDictionary)badIcon).FirstOrDefault(i =>
                                                                      ((PsbNumber)i.Value.Children("width")).AsInt == content["width"].AsInt &&
                                                                      ((PsbNumber)i.Value.Children("height")).AsInt == content["height"].AsInt &&
                                                                      ((PsbNumber)i.Value.Children("originX")).AsFloat == content["originX"].AsFloat &&
                                                                      ((PsbNumber)i.Value.Children("originY")).AsFloat == content["originY"].AsFloat);

                if (bi.Key != null)
                {
                    newIcon[bi.Key] = content;
                }
            }

            texGood["icon"] = newIcon;

            dynamic badSource = psbBad.Objects["source"];

            badSource["tex#000"] = texGood;

            psbBad.Merge();
            psbBad.BuildToFile("graft.psb");
        }
コード例 #10
0
        public static Dictionary <string, Bitmap> SplitTexture(PsbDictionary tex, PsbSpec spec)
        {
            var icon    = (PsbDictionary)tex["icon"];
            var texture = (PsbDictionary)tex["texture"];

            //var mipmap = (PsbDictionary)texture["mipMap"]; //TODO: Mipmap?
            Dictionary <string, Bitmap> textures = new Dictionary <string, Bitmap>(icon.Count);

            var md = PsbResCollector.GenerateMotionResMetadata(texture, (PsbResource)texture["pixel"]);

            md.Spec = spec; //Important
            Bitmap bmp = md.ToImage();

            foreach (var iconPair in icon)
            {
                var    info   = (PsbDictionary)iconPair.Value;
                var    width  = (int)(PsbNumber)info["width"];
                var    height = (int)(PsbNumber)info["height"];
                var    top    = (int)(PsbNumber)info["top"];
                var    left   = (int)(PsbNumber)info["left"];
                Bitmap b      = new Bitmap(width, height, PixelFormat.Format32bppArgb);
#if USE_FASTBITMAP
                using (FastBitmap f = b.FastLock())
                {
                    f.CopyRegion(bmp, new Rectangle(left, top, width, height), new Rectangle(0, 0, b.Width, b.Height));
                }
#else
                Graphics g = Graphics.FromImage(b);
                //g.InterpolationMode = InterpolationMode.NearestNeighbor;
                //g.PixelOffsetMode = PixelOffsetMode.Half;
                g.DrawImage(bmp, new Rectangle(0, 0, b.Width, b.Height), new Rectangle(left, top, width, height),
                            GraphicsUnit.Pixel);
                g.Dispose();
#endif
                textures.Add(iconPair.Key, b);
            }
            bmp.Dispose();
            return(textures);
        }
コード例 #11
0
        public bool TryGetArchData(PSB psb, PsbDictionary dic, out IArchData data)
        {
            data = null;
            if (psb.Platform == PsbSpec.win)
            {
                if (dic.Count == 1 && dic["archData"] is PsbDictionary archDic && archDic["data"] is PsbResource aData && archDic["dpds"] is PsbResource aDpds && archDic["fmt"] is PsbResource aFmt && archDic["wav"] is PsbString aWav)
                {
                    data = new XwmaArchData()
                    {
                        Data = aData,
                        Fmt  = aFmt,
                        Dpds = aDpds,
                        Wav  = aWav.Value
                    };

                    return(true);
                }

                return(false);
            }

            return(false);
        }
コード例 #12
0
        private void Add(PSB psb)
        {
            //add `easing`
            if (!psb.Objects.ContainsKey("easing"))
            {
                psb.Objects.Add("easing", new PsbCollection(0));
            }

            //add `/object/*/motion/*/bounds`
            //add `/object/*/motion/*/layerIndexMap`
            var obj = (PsbDictionary)psb.Objects["object"];

            foreach (var o in obj)
            {
                //var name = o.Key;
                foreach (var m in (PsbDictionary)((PsbDictionary)o.Value)["motion"])
                {
                    if (m.Value is PsbDictionary mDic)
                    {
                        if (!mDic.ContainsKey("bounds"))
                        {
                            var bounds = new PsbDictionary(4)
                            {
                                { "top", PsbNumber.Zero },
                                { "left", PsbNumber.Zero },
                                { "right", PsbNumber.Zero },
                                { "bottom", PsbNumber.Zero }
                            };
                            mDic.Add("bounds", bounds);
                        }


                        if (!(mDic["layer"] is PsbCollection col))
                        {
                            continue;
                        }

                        if (!mDic.ContainsKey("layerIndexMap"))
                        {
                            var layerIndexList = new List <string>();
                            LayerTravel(col, layerIndexList);
                            var layerIndexMap = new PsbDictionary(layerIndexList.Count);
                            int index         = 0;
                            foreach (var layerName in layerIndexList)
                            {
                                if (layerIndexMap.ContainsKey(layerName))
                                {
                                    continue;
                                }
                                layerIndexMap.Add(layerName, new PsbNumber(index));
                                index++;
                            }
                            mDic.Add("layerIndexMap", layerIndexMap);
                        }
                    }
                }
            }

            void LayerTravel(PsbCollection collection, List <string> indexList)
            {
                foreach (var col in collection)
                {
                    if (col is PsbDictionary dic && dic.ContainsKey("children"))
                    {
                        if (dic["label"] is PsbString str)
                        {
                            indexList.Add(str.Value);
                        }
                        if (dic["children"] is PsbCollection childrenCollection)
                        {
                            LayerTravel(childrenCollection, indexList);
                        }
                    }
                }
            }
        }
コード例 #13
0
        private Dictionary <string, (string Tex, string IconName)> TranslateResources(PSB psb)
        {
            Dictionary <string, (string Tex, string IconName)> iconInfos = new Dictionary <string, (string, string)>();
            Dictionary <string, Image> textures = new Dictionary <string, Image>();
            var  source        = (PsbDictionary)psb.Objects["source"];
            int  maxSideLength = 2048;
            long area          = 0;

            //Collect textures
            foreach (var tex in source)
            {
                var texName = tex.Key;
                var icons   = (PsbDictionary)((PsbDictionary)tex.Value)["icon"];
                foreach (var icon in icons)
                {
                    var iconName = icon.Key;
                    var info     = (PsbDictionary)icon.Value;
                    var width    = (int)(PsbNumber)info["width"];
                    var height   = (int)(PsbNumber)info["height"];
                    var res      = (PsbResource)info["pixel"];
                    var bmp      = info["compress"]?.ToString().ToUpperInvariant() == "RL"
                        ? RL.DecompressToImage(res.Data, height, width, psb.Platform.DefaultPixelFormat())
                        : RL.ConvertToImage(res.Data, height, width, psb.Platform.DefaultPixelFormat());
                    bmp.Tag = iconName;
                    textures.Add($"{texName}{Delimiter}{icon.Key}", bmp);
                    //estimate area and side length
                    area += width * height;
                    if (width >= maxSideLength || height >= maxSideLength)
                    {
                        maxSideLength = 4096;
                    }
                }
            }

            //Pack textures
            int size = 2048;

            if (maxSideLength > size || (area > 2048 * 2048 && psb.Header.Version > 2))
            {
                size = 4096;
            }
            int padding = TexturePadding >= 0 && TexturePadding <= 100 ? TexturePadding : 1;

            TexturePacker packer = new TexturePacker
            {
                FitHeuristic = FitHeuristic
            };

            packer.Process(textures, TextureSideLength ?? size, padding);

            //Add packed textures to source
            List <PsbDictionary> texs = new List <PsbDictionary>();

            for (var i = 0; i < packer.Atlasses.Count; i++)
            {
                var atlas = packer.Atlasses[i];
                var data  = UseRL
                    ? RL.CompressImage((Bitmap)atlas.ToImage(), TargetPixelFormat)
                    : RL.GetPixelBytesFromImage(atlas.ToImage(), TargetPixelFormat);

                var texDic = new PsbDictionary(4);
                //metadata
                texDic.Add("metadata", new PsbString(i.ToString("D3")));
                var texName = $"tex#{texDic["metadata"]}";
                //icon
                var icons = new PsbDictionary(atlas.Nodes.Count);
                texDic.Add("icon", icons);
                int id = 0;
                foreach (var node in atlas.Nodes)
                {
                    if (node.Texture == null)
                    {
                        continue;
                    }
                    var paths = node.Texture.Source.Split(new[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
                    var icon  = (PsbDictionary)source[paths[0]].Children("icon").Children(paths[1]);
                    icon.Remove("compress");
                    icon.Remove("pixel");
                    icon["attr"] = PsbNumber.Zero;
                    icon["left"] = new PsbNumber(node.Bounds.Left);
                    icon["top"]  = new PsbNumber(node.Bounds.Top);
                    icon.Parent  = icons;
                    var iconName = UseMeaningfulName ? node.Texture.Source : id.ToString();
                    icons.Add(iconName, icon);
                    iconInfos.Add(node.Texture.Source, (texName, iconName));
                    id++;
                }
                //texture
                //TODO: support truncated
                var texture = new PsbDictionary(6)
                {
                    { "height", new PsbNumber(atlas.Height) },
                    { "width", new PsbNumber(atlas.Width) },
                    { "truncated_height", new PsbNumber(atlas.Height) },
                    { "truncated_width", new PsbNumber(atlas.Width) },
                    { "type", new PsbString(TargetPixelFormat.ToStringForPsb()) }
                };
                texture.Add("pixel", new PsbResource {
                    Data = data, Parents = new List <IPsbCollection> {
                        texture
                    }
                });
                texDic.Add("texture", texture);
                //type
                texDic.Add("type", PsbNumber.Zero);

                texs.Add(texDic);
            }

            source.Clear();
            foreach (var t in texs)
            {
                source.Add($"tex#{t["metadata"]}", t);
                t["metadata"] = PsbNull.Null;
            }
            return(iconInfos);
        }
コード例 #14
0
ファイル: Program.cs プロジェクト: parhelia512/FreeMote
        /// <summary>
        /// Pack Archive PSB
        /// </summary>
        /// <param name="jsonPath">json path</param>
        /// <param name="key">crypt key</param>
        /// <param name="intersect">Only pack files which existed in info.psb.m</param>
        /// <param name="preferPacked">Prefer using PSB files rather than json files in source folder</param>
        /// <param name="enableParallel">parallel process</param>
        /// <param name="keyLen">key length</param>
        /// <param name="keepRaw">Do not try to compile json or pack MDF</param>
        public static void PackArchive(string jsonPath, string key, bool intersect, bool preferPacked, bool enableParallel = true,
                                       int keyLen = 131, bool keepRaw = false)
        {
            if (!File.Exists(jsonPath))
            {
                return;
            }
            PSB infoPsb = PsbCompiler.LoadPsbFromJsonFile(jsonPath);

            if (infoPsb.Type != PsbType.ArchiveInfo)
            {
                Console.WriteLine("Json is not an ArchiveInfo PSB.");
                return;
            }

            var resx = PsbResourceJson.LoadByPsbJsonPath(jsonPath);

            if (!resx.Context.ContainsKey(Context_ArchiveSource) ||
                resx.Context[Context_ArchiveSource] == null)
            {
                Console.WriteLine("ArchiveSource must be specified in resx.json Context.");
                return;
            }

            if (keyLen > 0)
            {
                resx.Context[Context_MdfKeyLength] = keyLen;
            }

            string infoKey = null;

            if (resx.Context[Context_MdfKey] is string mdfKey)
            {
                infoKey = mdfKey;
            }

            List <string> sourceDirs = null;

            if (resx.Context[Context_ArchiveSource] is string path)
            {
                sourceDirs = new List <string> {
                    path
                };
            }
            else if (resx.Context[Context_ArchiveSource] is IList paths)
            {
                sourceDirs = new List <string>(paths.Count);
                sourceDirs.AddRange(from object p in paths select p.ToString());
            }
            else
            {
                Console.WriteLine("ArchiveSource incorrect.");
                return;
            }

            var           baseDir = Path.GetDirectoryName(jsonPath);
            var           files   = new Dictionary <string, (string Path, ProcessMethod Method)>();
            var           suffix  = ArchiveInfoGetSuffix(infoPsb);
            List <string> filter  = null;

            if (intersect) //only collect files appeared in json
            {
                filter = ArchiveInfoCollectFiles(infoPsb, suffix).ToList();
            }

            void CollectFiles(string targetDir)
            {
                if (!Directory.Exists(targetDir))
                {
                    return;
                }

                foreach (var f in Directory.EnumerateFiles(targetDir))
                {
                    if (f.EndsWith(".resx.json", true, CultureInfo.InvariantCulture))
                    {
                        continue;
                    }
                    else if (f.EndsWith(".json", true, CultureInfo.InvariantCulture)) //json source, need compile
                    {
                        var name = Path.GetFileNameWithoutExtension(f);
                        if (preferPacked && files.ContainsKey(name) &&
                            files[name].Method != ProcessMethod.Compile) //it's always right no matter set or replace
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name)) //this file is not appeared in json
                            {
                                //ignore
                            }
                            else
                            {
                                files[name] = (f, keepRaw? ProcessMethod.None: ProcessMethod.Compile);
                            }
                        }
                    }
                    else
                    {
                        var name = Path.GetFileName(f);
                        if (!preferPacked && files.ContainsKey(name) &&
                            files[name].Method == ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                using var fs = File.OpenRead(f);
                                if (!MdfFile.IsSignatureMdf(fs) && name.DefaultShellType() == "MDF")
                                {
                                    files[name] = (f, keepRaw? ProcessMethod.None: ProcessMethod.EncodeMdf);
                                }
                                else
                                {
                                    files[name] = (f, ProcessMethod.None);
                                }
                            }
                        }
                    }
                }
            }

            //Collect files
            Console.WriteLine("Collecting files ...");
            foreach (var sourceDir in sourceDirs)
            {
                CollectFiles(Path.IsPathRooted(sourceDir) ? sourceDir : Path.Combine(baseDir, sourceDir));
            }

            Console.WriteLine($"Packing {files.Count} files ...");
            var bodyBinFileName = Path.GetFileName(jsonPath);
            var packageName     = Path.GetFileNameWithoutExtension(bodyBinFileName);

            var coreName = ArchiveInfoGetPackageName(packageName);

            bodyBinFileName = string.IsNullOrEmpty(coreName) ? packageName + "_body.bin" : coreName + "_body.bin";

            //using var mmFile =
            //    MemoryMappedFile.CreateFromFile(bodyBinFileName, FileMode.Create, coreName, );
            using var bodyFs = File.OpenWrite(bodyBinFileName);
            var fileInfoDic = new PsbDictionary(files.Count);
            var fmContext   = FreeMount.CreateContext(resx.Context);

            //byte[] bodyBin = null;
            if (enableParallel)
            {
                var contents = new ConcurrentBag <(string Name, Stream Content)>();
                Parallel.ForEach(files, (kv) =>
                {
                    var fileNameWithoutSuffix = ArchiveInfoGetFileNameRemoveSuffix(kv.Key, suffix);

                    if (kv.Value.Method == ProcessMethod.None)
                    {
                        contents.Add((fileNameWithoutSuffix, File.OpenRead(kv.Value.Path)));
                        return;
                    }

                    var mdfContext = new Dictionary <string, object>(resx.Context);
                    var context    = FreeMount.CreateContext(mdfContext);
                    if (!string.IsNullOrEmpty(key))
                    {
                        mdfContext[Context_MdfKey] = key + kv.Key;
                    }
                    else if (resx.Context[Context_MdfMtKey] is string mtKey)
                    {
                        mdfContext[Context_MdfKey] = mtKey + kv.Key;
                    }
                    else
                    {
                        mdfContext.Remove(Context_MdfKey);
                    }

                    mdfContext.Remove(Context_ArchiveSource);

                    if (kv.Value.Method == ProcessMethod.EncodeMdf)
                    {
                        using var mmFs = MemoryMappedFile.CreateFromFile(kv.Value.Path, FileMode.Open);

                        //using var fs = File.OpenRead(kv.Value.Path);
                        contents.Add((fileNameWithoutSuffix, context.PackToShell(mmFs.CreateViewStream(), "MDF"))); //disposed later
                    }
                    else
                    {
                        var content   = PsbCompiler.LoadPsbAndContextFromJsonFile(kv.Value.Path);
                        var stream    = content.Psb.ToStream();
                        var shellType = kv.Key.DefaultShellType(); //MARK: use shellType in filename, or use suffix in info?
                        if (!string.IsNullOrEmpty(shellType))
                        {
                            stream = context.PackToShell(stream, shellType); //disposed later
                        }
                        contents.Add((fileNameWithoutSuffix, stream));
                    }
                });
コード例 #15
0
ファイル: PsbResCollector.cs プロジェクト: jszhtian/FreeMote
        /// <summary>
        /// Extract resource info
        /// </summary>
        /// <param name="d">PsbObject which contains "pixel"</param>
        /// <param name="r">Resource</param>
        /// <returns></returns>
        internal static ResourceMetadata GenerateMotionResMetadata(PsbDictionary d, PsbResource r = null)
        {
            if (r == null)
            {
                r = d.Values.FirstOrDefault(v => v is PsbResource) as PsbResource;
            }
            bool       is2D = false;
            var        part = d.GetPartName();
            var        name = d.GetName();
            RectangleF clip = RectangleF.Empty;

            if (d["clip"] is PsbDictionary clipDic && clipDic.Count > 0)
            {
                is2D = true;
                clip = RectangleF.FromLTRB(
                    left: clipDic["left"] == null ? 0f : (float)(PsbNumber)clipDic["left"],
                    top: clipDic["top"] == null ? 0f : (float)(PsbNumber)clipDic["top"],
                    right: clipDic["right"] == null ? 1f : (float)(PsbNumber)clipDic["right"],
                    bottom: clipDic["bottom"] == null ? 1f : (float)(PsbNumber)clipDic["bottom"]
                    );
            }
            var compress = PsbCompressType.None;

            if (d["compress"] is PsbString sc)
            {
                is2D = true;
                if (sc.Value.ToUpperInvariant() == "RL")
                {
                    compress = PsbCompressType.RL;
                }
            }
            int   width = 1, height = 1;
            float originX = 0, originY = 0;

            if (d["width"] is PsbNumber nw)
            {
                is2D  = true;
                width = (int)nw;
            }
            if (d["height"] is PsbNumber nh)
            {
                is2D   = true;
                height = (int)nh;
            }
            if (d["originX"] is PsbNumber nx)
            {
                is2D    = true;
                originX = (float)nx;
            }
            if (d["originY"] is PsbNumber ny)
            {
                is2D    = true;
                originY = (float)ny;
            }

            PsbString typeString = null;

            if (d["type"] is PsbString typeStr)
            {
                typeString = typeStr;
            }
            int top = 0, left = 0;

            if (d["top"] is PsbNumber nt)
            {
                is2D = true;
                top  = (int)nt;
            }
            if (d["left"] is PsbNumber nl)
            {
                is2D = true;
                left = (int)nl;
            }
            var md = new ResourceMetadata()
            {
                Index      = r.Index ?? int.MaxValue,
                Compress   = compress,
                Name       = name,
                Part       = part,
                Clip       = clip,
                Is2D       = is2D,
                OriginX    = originX,
                OriginY    = originY,
                Top        = top,
                Left       = left,
                Width      = width,
                Height     = height,
                TypeString = typeString,
                Resource   = r,
            };

            return(md);
        }
コード例 #16
0
ファイル: Program.cs プロジェクト: RadioJah/FreeMote
        /// <summary>
        /// Pack Archive PSB
        /// </summary>
        /// <param name="jsonPath">json path</param>
        /// <param name="key">crypt key</param>
        /// <param name="intersect">Only pack files which existed in info.psb.m</param>
        /// <param name="preferPacked">Prefer using PSB files rather than json files in source folder</param>
        /// <param name="enableParallel">parallel process</param>
        /// <param name="keyLen">key length</param>
        public static void PackArchive(string jsonPath, string key, bool intersect, bool preferPacked, bool enableParallel = true,
                                       int keyLen = 131)
        {
            if (!File.Exists(jsonPath))
            {
                return;
            }
            PSB infoPsb = PsbCompiler.LoadPsbFromJsonFile(jsonPath);

            if (infoPsb.Type != PsbType.ArchiveInfo)
            {
                Console.WriteLine("Json is not an ArchiveInfo PSB.");
                return;
            }

            var resx = PsbResourceJson.LoadByPsbJsonPath(jsonPath);

            if (!resx.Context.ContainsKey(Context_ArchiveSource) ||
                resx.Context[Context_ArchiveSource] == null)
            {
                Console.WriteLine("ArchiveSource must be specified in resx.json Context.");
                return;
            }

            if (keyLen > 0)
            {
                resx.Context[Context_MdfKeyLength] = keyLen;
            }

            string infoKey = null;

            if (resx.Context[Context_MdfKey] is string mdfKey)
            {
                infoKey = mdfKey;
            }

            List <string> sourceDirs = null;

            if (resx.Context[Context_ArchiveSource] is string path)
            {
                sourceDirs = new List <string> {
                    path
                };
            }
            else if (resx.Context[Context_ArchiveSource] is IList paths)
            {
                sourceDirs = new List <string>(paths.Count);
                sourceDirs.AddRange(from object p in paths select p.ToString());
            }
            else
            {
                Console.WriteLine("ArchiveSource incorrect.");
                return;
            }

            var           baseDir = Path.GetDirectoryName(jsonPath);
            var           files   = new Dictionary <string, (string Path, ProcessMethod Method)>();
            var           suffix  = ArchiveInfoPsbGetSuffix(infoPsb);
            List <string> filter  = null;

            if (intersect)
            {
                filter = ArchiveInfoPsbCollectFiles(infoPsb, suffix);
            }

            void CollectFiles(string targetDir)
            {
                if (!Directory.Exists(targetDir))
                {
                    return;
                }

                foreach (var f in Directory.EnumerateFiles(targetDir))
                {
                    if (f.EndsWith(".resx.json", true, CultureInfo.InvariantCulture))
                    {
                        continue;
                    }
                    else if (f.EndsWith(".json", true, CultureInfo.InvariantCulture))
                    {
                        var name = Path.GetFileNameWithoutExtension(f);
                        if (preferPacked && files.ContainsKey(name) &&
                            files[name].Method != ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                files[name] = (f, ProcessMethod.Compile);
                            }
                        }
                    }
                    else
                    {
                        var name = Path.GetFileName(f);
                        if (!preferPacked && files.ContainsKey(name) &&
                            files[name].Method == ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                using var fs = File.OpenRead(f);
                                if (!MdfFile.IsSignatureMdf(fs) && name.DefaultShellType() == "MDF")
                                {
                                    files[name] = (f, ProcessMethod.EncodeMdf);
                                }
                                else
                                {
                                    files[name] = (f, ProcessMethod.None);
                                }
                            }
                        }
                    }
                }
            }

            //Collect files
            foreach (var sourceDir in sourceDirs)
            {
                CollectFiles(Path.IsPathRooted(sourceDir) ? sourceDir : Path.Combine(baseDir, sourceDir));
            }

            var fileName    = Path.GetFileName(jsonPath);
            var packageName = Path.GetFileNameWithoutExtension(fileName);

            var coreName = PsbExtension.ArchiveInfoGetPackageName(packageName);

            fileName = string.IsNullOrEmpty(coreName) ? packageName + "_body.bin" : coreName + "_body.bin";

            var fileInfoDic = new PsbDictionary(files.Count);
            var fmContext   = FreeMount.CreateContext(resx.Context);

            byte[] bodyBin = null;
            if (enableParallel)
            {
                var contents = new ConcurrentBag <(string Name, Stream Content)>();
                Parallel.ForEach(files, (kv) =>
                {
                    var fileNameWithoutSuffix = ArchiveInfoPsbGetFileName(kv.Key, suffix);
                    if (kv.Value.Method == ProcessMethod.None)
                    {
                        contents.Add((fileNameWithoutSuffix, File.OpenRead(kv.Value.Path)));
                        return;
                    }

                    var mdfContext = new Dictionary <string, object>(resx.Context);
                    var context    = FreeMount.CreateContext(mdfContext);
                    if (!string.IsNullOrEmpty(key))
                    {
                        mdfContext[Context_MdfKey] = key + fileNameWithoutSuffix + suffix;
                    }
                    else if (resx.Context[Context_MdfMtKey] is string mtKey)
                    {
                        mdfContext[Context_MdfKey] =
                            mtKey + fileNameWithoutSuffix + suffix;
                    }
                    else
                    {
                        mdfContext.Remove(Context_MdfKey);
                    }

                    mdfContext.Remove(Context_ArchiveSource);

                    if (kv.Value.Method == ProcessMethod.EncodeMdf)
                    {
                        contents.Add((fileNameWithoutSuffix, context.PackToShell(
                                          File.OpenRead(kv.Value.Path), "MDF")));
                    }
                    else
                    {
                        var content = PsbCompiler.LoadPsbAndContextFromJsonFile(kv.Value.Path);

                        var outputMdf = context.PackToShell(content.Psb.ToStream(), "MDF");
                        contents.Add((fileNameWithoutSuffix, outputMdf));
                    }
                });
コード例 #17
0
        /// <summary>
        /// Extract resource info
        /// </summary>
        /// <param name="d">PsbObject which contains "pixel"</param>
        /// <param name="r">Resource</param>
        /// <param name="duplicatePalette">When set to true, Pal.Data may not be set!</param>
        /// <returns></returns>
        internal static ImageMetadata GenerateImageMetadata(PsbDictionary d, PsbResource r = null,
                                                            bool duplicatePalette          = false)
        {
            if (r == null)
            {
                if (d.ContainsKey(Consts.ResourceKey) && d[Consts.ResourceKey] is PsbResource rr)
                {
                    r = rr;
                }
                else //this may find Pal
                {
                    r = d.Values.FirstOrDefault(v => v is PsbResource) as PsbResource;
                }
            }

            bool       is2D = false;
            var        part = GetPartName(d);
            var        name = d.GetName();
            RectangleF clip = RectangleF.Empty;

            if (d["clip"] is PsbDictionary clipDic && clipDic.Count > 0)
            {
                is2D = true;
                clip = RectangleF.FromLTRB(
                    left: clipDic["left"] == null ? 0f : (float)(PsbNumber)clipDic["left"],
                    top: clipDic["top"] == null ? 0f : (float)(PsbNumber)clipDic["top"],
                    right: clipDic["right"] == null ? 1f : (float)(PsbNumber)clipDic["right"],
                    bottom: clipDic["bottom"] == null ? 1f : (float)(PsbNumber)clipDic["bottom"]
                    );
            }

            var compress = PsbCompressType.None;

            if (d["compress"] is PsbString sc)
            {
                is2D = true;
                if (sc.Value.ToUpperInvariant() == "RL")
                {
                    compress = PsbCompressType.RL;
                }
            }

            int   width = 1, height = 1;
            float originX = 0, originY = 0;

            if (d["width"] is PsbNumber nw)
            {
                is2D  = true;
                width = (int)nw;
            }

            if (d["height"] is PsbNumber nh)
            {
                is2D   = true;
                height = (int)nh;
            }

            if (d["originX"] is PsbNumber nx)
            {
                is2D    = true;
                originX = (float)nx;
            }

            if (d["originY"] is PsbNumber ny)
            {
                is2D    = true;
                originY = (float)ny;
            }

            PsbString typeString = null;

            if (d["type"] is PsbString typeStr)
            {
                typeString = typeStr;
            }

            int top = 0, left = 0;

            if (d["top"] is PsbNumber nt)
            {
                is2D = true;
                top  = (int)nt;
            }

            if (d["left"] is PsbNumber nl)
            {
                is2D = true;
                left = (int)nl;
            }

            PsbResource palResource   = null;
            PsbString   palTypeString = null;

            if (d["pal"] is PsbResource palRes)
            {
                if (duplicatePalette)
                {
                    palResource = new PsbResource(palRes.Index);
                    d["pal"]    = palResource;
                }
                else
                {
                    palResource = palRes;
                }

                palTypeString = d["palType"] as PsbString;
            }

            var md = new ImageMetadata()
            {
                Index             = r.Index ?? int.MaxValue,
                Compress          = compress,
                Name              = name,
                Part              = part,
                Clip              = clip,
                Is2D              = is2D,
                OriginX           = originX,
                OriginY           = originY,
                Top               = top,
                Left              = left,
                Width             = width,
                Height            = height,
                TypeString        = typeString,
                Resource          = r,
                Palette           = palResource,
                PaletteTypeString = palTypeString
            };

            return(md);
        }
コード例 #18
0
ファイル: PsbJsonConverter.cs プロジェクト: RadioJah/FreeMote
        internal IPsbValue ConvertToken(JToken token, Dictionary <string, PsbString> context)
        {
            switch (token.Type)
            {
            case JTokenType.Null:
                return(PsbNull.Null);

            case JTokenType.Integer:
                var l = token.Value <long>();
                if (l > Int32.MaxValue || l < Int32.MinValue)
                {
                    return(new PsbNumber(l));
                }
                return(new PsbNumber(token.Value <int>()));

            case JTokenType.Float:
                //var numberStr = token.Value<string>();
                var d = token.Value <double>();
                if (UseDoubleOnly)
                {
                    return(new PsbNumber(d));
                }
                var f = token.Value <float>();
                if (Math.Abs(f - d) < 1E-08)     //float //pcc: 1E-05
                //if (Math.Abs(f - d) < float.Epsilon)
                {
                    return(new PsbNumber(f));
                }
                //if (d < float.MaxValue && d > float.MinValue)
                //{
                //    return new PsbNumber(token.Value<float>());
                //}
                return(new PsbNumber(d));

            case JTokenType.Boolean:
                return(new PsbBool(token.Value <bool>()));

            case JTokenType.String:
                string str = token.Value <string>();
                if (str.StartsWith(Consts.NumberStringPrefix))
                {
                    var prefixLen = Consts.NumberStringPrefix.Length;
                    if (str.EndsWith("f"))
                    {
                        return(new PsbNumber(int.Parse(str.Substring(prefixLen, 8), NumberStyles.AllowHexSpecifier))
                        {
                            NumberType = PsbNumberType.Float
                        });
                    }
                    if (str.EndsWith("d"))
                    {
                        return(new PsbNumber(long.Parse(str.Substring(prefixLen, 16), NumberStyles.AllowHexSpecifier))
                        {
                            NumberType = PsbNumberType.Double
                        });
                    }
                    return(new PsbNumber(long.Parse(str.Substring(prefixLen), NumberStyles.AllowHexSpecifier)));
                }
                if (str.StartsWith(Consts.ResourceIdentifier))
                {
                    return(new PsbResource(uint.Parse(str.Replace(Consts.ResourceIdentifier, ""))));
                }
                var psbStr = new PsbString(str, (uint)context.Count);
                if (context.ContainsKey(str))
                {
                    return(context[str]);
                }
                else
                {
                    context.Add(str, psbStr);
                }
                return(psbStr);

            case JTokenType.Array:
                var array      = (JArray)token;
                var collection = new PsbList(array.Count);
                foreach (var val in array)
                {
                    var o = ConvertToken(val, context);
                    if (o is IPsbChild c)
                    {
                        c.Parent = collection;
                    }
                    if (o is IPsbSingleton s)
                    {
                        s.Parents.Add(collection);
                    }
                    collection.Add(o);
                }
                return(collection);

            case JTokenType.Object:
                var obj        = (JObject)token;
                var dictionary = new PsbDictionary(obj.Count);
                foreach (var val in obj)
                {
                    var o = ConvertToken(val.Value, context);
                    if (o is IPsbChild c)
                    {
                        c.Parent = dictionary;
                    }
                    if (o is IPsbSingleton s)
                    {
                        s.Parents.Add(dictionary);
                    }
                    dictionary.Add(val.Key, o);
                }
                return(dictionary);

            default:
                throw new FormatException("Unsupported json element");
            }
        }
コード例 #19
0
        public static IEnumerable <IPsbValue> FindAllByPath(this PsbDictionary psbObj, string path)
        {
            if (psbObj == null)
            {
                yield break;
            }
            if (path.StartsWith("/"))
            {
                path = new string(path.SkipWhile(c => c == '/').ToArray());
            }

            if (path.Contains("/"))
            {
                var pos     = path.IndexOf('/');
                var current = path.Substring(0, pos);
                if (current == "*")
                {
                    if (pos == path.Length - 1) //end
                    {
                        if (psbObj is PsbDictionary dic)
                        {
                            foreach (var dicValue in dic.Values)
                            {
                                yield return(dicValue);
                            }
                        }
                    }

                    path = new string(path.SkipWhile(c => c == '*').ToArray());
                    foreach (var val in psbObj.Values)
                    {
                        if (val is PsbDictionary dic)
                        {
                            foreach (var dicValue in dic.FindAllByPath(path))
                            {
                                yield return(dicValue);
                            }
                        }
                    }
                }

                if (pos == path.Length - 1 && psbObj[current] != null)
                {
                    yield return(psbObj[current]);
                }

                var currentObj = psbObj[current];
                if (currentObj is PsbDictionary collection)
                {
                    path = path.Substring(pos);
                    foreach (var dicValue in collection.FindAllByPath(path))
                    {
                        yield return(dicValue);
                    }
                }
            }

            if (path == "*")
            {
                foreach (var value in psbObj.Values)
                {
                    yield return(value);
                }
            }
            else if (psbObj[path] != null)
            {
                yield return(psbObj[path]);
            }
        }
コード例 #20
0
        internal IPsbValue ConvertToken(JToken token, List <PsbString> context)
        {
            switch (token.Type)
            {
            case JTokenType.Null:
                return(PsbNull.Null);

            case JTokenType.Integer:
                return(new PsbNumber(token.Value <int>()));

            case JTokenType.Float:
                var d = token.Value <double>();
                var f = token.Value <float>();
                if (Math.Abs(f - d) < 1E-05)     //float //pcc: 1E-05
                {
                    return(new PsbNumber(token.Value <float>()));
                }
                //if (d < float.MaxValue && d > float.MinValue)
                //{
                //    return new PsbNumber(token.Value<float>());
                //}
                return(new PsbNumber(d));

            case JTokenType.Boolean:
                return(new PsbBool(token.Value <bool>()));

            case JTokenType.String:
                string str = token.Value <string>();
                if (str.StartsWith(PsbResCollector.ResourceIdentifier))
                {
                    return(new PsbResource(uint.Parse(str.Replace(PsbResCollector.ResourceIdentifier, ""))));
                }
                var psbStr = new PsbString(str, (uint)context.Count);
                if (context.Contains(psbStr))
                {
                    return(context.Find(ps => ps.Value == str));
                }
                else
                {
                    context.Add(psbStr);
                }
                return(psbStr);

            case JTokenType.Array:
                var array      = (JArray)token;
                var collection = new PsbCollection(array.Count);
                foreach (var val in array)
                {
                    var o = ConvertToken(val, context);
                    if (o is IPsbChild c)
                    {
                        c.Parent = collection;
                    }
                    if (o is IPsbSingleton s)
                    {
                        s.Parents.Add(collection);
                    }
                    collection.Add(o);
                }
                return(collection);

            case JTokenType.Object:
                var obj        = (JObject)token;
                var dictionary = new PsbDictionary(obj.Count);
                foreach (var val in obj)
                {
                    var o = ConvertToken(val.Value, context);
                    if (o is IPsbChild c)
                    {
                        c.Parent = dictionary;
                    }
                    if (o is IPsbSingleton s)
                    {
                        s.Parents.Add(dictionary);
                    }
                    dictionary.Add(val.Key, o);
                }
                return(dictionary);

            default:
                throw new FormatException("Unsupported json element");
            }
        }