Example #1
0
        /// <summary>
        /// Link
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="resx">advanced resource json(resx.jon)</param>
        /// <param name="baseDir"></param>
        internal static void Link(this PSB psb, PsbResourceJson resx, string baseDir)
        {
            FreeMountContext context = FreeMount.CreateContext(resx.Context);
            var resList = psb.CollectResources();

            foreach (var resxResource in resx.Resources)
            {
                //Scan for Resource
                var resMd = resList.FirstOrDefault(r =>
                                                   resxResource.Key == r.GetFriendlyName(psb.Type));
                if (resMd == null && psb.Type == PsbType.Pimg)
                {
                    resMd = resList.FirstOrDefault(r => resxResource.Key == Path.GetFileNameWithoutExtension(r.Name));
                }

                if (resMd == null && uint.TryParse(resxResource.Key, out uint rid))
                {
                    resMd = resList.FirstOrDefault(r => r.Index == rid);
                }

                if (resMd == null)
                {
                    Console.WriteLine($"[WARN]{resxResource.Key} is not used.");
                    continue;
                }

                var fullPath = Path.IsPathRooted(resxResource.Value)
                    ? resxResource.Value
                    : Path.Combine(baseDir ?? "", resxResource.Value.Replace('/', '\\'));
                byte[] data = LoadImageBytes(fullPath, resMd, context);
                resMd.Resource.Data = data;
            }
        }
Example #2
0
        public void Link(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null,
                         PsbLinkOrderBy order = PsbLinkOrderBy.Convention)
        {
            var rawResList = psb.CollectResources <AudioMetadata>();

            if (order == PsbLinkOrderBy.Order)
            {
                for (int i = 0; i < rawResList.Count; i++)
                {
                    var resMd    = rawResList[i];
                    var fullPath = Path.Combine(baseDir ?? "", resPaths[i]);
                    resMd.Link(fullPath, context);
                }

                return;
            }

            foreach (var resPath in resPaths)
            {
                var resMd = rawResList.FirstOrDefault(r => r.Name == Path.GetFileNameWithoutExtension(resPath));
                if (resMd == null)
                {
                    Console.WriteLine($"[WARN] {resPath} is not used.");
                    continue;
                }

                var fullPath = Path.Combine(baseDir ?? "", resPath);
                resMd.Link(fullPath, context);
            }
        }
Example #3
0
        public bool TryToWave(FreeMountContext context, out List <byte[]> waveChannels)
        {
            waveChannels = null;
            if (context == null)
            {
                return(false);
            }

            waveChannels = new List <byte[]>(ChannelList.Count);
            var result = true;

            foreach (var channel in ChannelList)
            {
                var bytes = channel.TryToWave(context);
                if (bytes == null)
                {
                    result = false;
                }
                else
                {
                    waveChannels.Add(bytes);
                }
            }

            return(result);
        }
Example #4
0
        public void Link(PSB psb, FreeMountContext context, IDictionary <string, string> resPaths, string baseDir = null)
        {
            var rawResList = psb.CollectResources <AudioMetadata>();

            foreach (var resPath in resPaths)
            {
                var fullPath = Path.Combine(baseDir ?? "", resPath.Value);
                var resMd    = rawResList.FirstOrDefault(r => r.Name == resPath.Key);
                if (resMd == null)
                {
                    if (uint.TryParse(resPath.Key, out var idx))
                    {
                        var resource = psb.Resources.FirstOrDefault(r => r.Index == idx);
                        if (resource != null)
                        {
                            resource.Data = File.ReadAllBytes(fullPath);
                        }
                        else
                        {
                            Console.WriteLine($"[WARN] {resPath.Key} is not used.");
                        }
                    }
                }
                else
                {
                    resMd.Link(fullPath, context);
                }
            }
        }
Example #5
0
        internal static void LinkImages(PSB psb, FreeMountContext context, IDictionary <string, string> resources,
                                        string baseDir = null)
        {
            var resList = psb.CollectResources <ImageMetadata>();

            foreach (var resxResource in resources)
            {
                //Scan for Resource
                var resMd = resList.FirstOrDefault(r =>
                                                   resxResource.Key == r.GetFriendlyName(psb.Type));
                if (resMd == null && psb.Type == PsbType.Pimg)
                {
                    resMd = resList.FirstOrDefault(r => resxResource.Key == Path.GetFileNameWithoutExtension(r.Name));
                }

                if (resMd == null && resxResource.Key.StartsWith("##") && int.TryParse(resxResource.Key.Substring(2), out int rIdx))
                {
                    resMd = resList[rIdx];
                }

                if (resMd == null && uint.TryParse(resxResource.Key, out uint rid))
                {
                    resMd = resList.FirstOrDefault(r => r.Index == rid);
                    if (resMd == null)
                    {
                        //support raw palette
                        var palResMds = resList.FindAll(r => r.Palette?.Index == rid);
                        if (palResMds.Count > 0)
                        {
                            var palFullPath = Path.IsPathRooted(resxResource.Value)
                                ? resxResource.Value
                                : Path.Combine(baseDir ?? "", resxResource.Value.Replace('/', '\\'));
                            var palRawData = File.ReadAllBytes(palFullPath);
                            foreach (var palResMd in palResMds)
                            {
                                palResMd.PalData = palRawData;
                            }

                            continue;
                        }
                    }
                }

                if (resMd == null)
                {
                    Console.WriteLine($"[WARN]{resxResource.Key} is not used.");
                    continue;
                }

                var fullPath = Path.IsPathRooted(resxResource.Value)
                    ? resxResource.Value
                    : Path.Combine(baseDir ?? "", resxResource.Value.Replace('/', '\\'));
                resMd.Link(fullPath, context);
            }
        }
Example #6
0
        public Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                           PsbExtractOption extractOption = PsbExtractOption.Original)
        {
            var resources = psb.CollectResources <AudioMetadata>();
            Dictionary <string, string> resDictionary = new Dictionary <string, string>();

            if (extractOption == PsbExtractOption.Original)
            {
                for (int i = 0; i < psb.Resources.Count; i++)
                {
                    var relativePath = psb.Resources[i].Index == null ? $"#{i}.raw" : $"{psb.Resources[i].Index}.raw";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.Resources[i].Data);
                    resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}");
                }
            }
            else
            {
                foreach (var resource in resources)
                {
                    if (resource.ChannelList.Count == 1)
                    {
                        var bts          = resource.ChannelList[0].TryToWave(context);
                        var relativePath = resource.GetFileName(resource.ChannelList[0].WaveExtension); //WaveExtension may change after ToWave
                        if (bts != null)
                        {
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts);
                            resDictionary.Add(resource.Name, $"{name}/{relativePath}");
                        }
                    }
                    else if (resource.ChannelList.Count > 1)
                    {
                        for (var j = 0; j < resource.ChannelList.Count; j++)
                        {
                            var waveChannel  = resource.ChannelList[j];
                            var bts          = waveChannel.TryToWave(context);
                            var relativePath = resource.GetFileName($"-{j}{waveChannel.WaveExtension}");
                            if (bts != null)
                            {
                                File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts);
                                resDictionary.Add(resource.Name, $"{name}/{relativePath}");
                            }
                        }
                    }
                }
            }

            return(resDictionary);
        }
Example #7
0
        public void Link(string fullPath, FreeMountContext context)
        {
            if (ChannelList.Count > 1)
            {
                Console.WriteLine("[WARN] Audio with multiple channels is not supported. Send me the sample for research.");
            }

            var ext = Path.GetExtension(fullPath).ToLowerInvariant();

            switch (ext)
            {
            case ".at9":
                var at9Arch = (Atrac9ArchData)ChannelList[0];
                at9Arch.Data.Data = File.ReadAllBytes(fullPath);
                break;

            case ".xwma":
                var xwmaArch = (XwmaArchData)ChannelList[0];
                xwmaArch.ReadFromXwma(File.OpenRead(fullPath));
                break;

            case ".wav":
            case ".ogg":
                var newArch = context.WaveToArchData(ChannelList[0].Extension, File.ReadAllBytes(fullPath),
                                                     ChannelList[0].WaveExtension);
                if (newArch != null)
                {
                    ChannelList[0].SetPsbArchData(newArch.ToPsbArchData());
                }
                else
                {
                    if (ChannelList[0].Extension == ext)
                    {
                        LoadFromRawFile(ChannelList[0], fullPath);
                    }
                    else
                    {
                        Console.WriteLine(
                            $"[WARN] There is no encoder for {ChannelList[0].Extension}! {fullPath} is not used.");
                    }
                }

                break;

            case ".bin":
            case ".raw":
            default:
                LoadFromRawFile(ChannelList[0], fullPath);
                break;
            }
        }
Example #8
0
        public override Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                                    PsbExtractOption extractOption = PsbExtractOption.Original)
        {
            //Extra Extract
            if (extractOption == PsbExtractOption.Extract)
            {
                if (psb.Type == PsbType.Tachie)
                {
                    var bitmaps = TextureCombiner.CombineTachie(psb);
                    foreach (var kv in bitmaps)
                    {
                        kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{context.ImageFormat.DefaultExtension()}"), context.ImageFormat.ToImageFormat());
                    }
                }
            }

            return(base.OutputResources(psb, context, name, dirPath, extractOption));
        }
Example #9
0
        public static void UnlinkImagesToFile(PSB psb, FreeMountContext context, string name, string dirPath,
                                              bool disposeResInPsb = true,
                                              PsbLinkOrderBy order = PsbLinkOrderBy.Name)
        {
            var texs = UnlinkImages(psb, order, disposeResInPsb);

            var texExt    = context.ImageFormat.DefaultExtension();
            var texFormat = context.ImageFormat.ToImageFormat();

            switch (order)
            {
            case PsbLinkOrderBy.Convention:
                foreach (var tex in texs)
                {
                    tex.Save(Path.Combine(dirPath, tex.Tag + texExt), texFormat);
                }

                break;

            case PsbLinkOrderBy.Name:
                foreach (var tex in texs)
                {
                    tex.Save(Path.Combine(dirPath, $"{name}_{tex.Tag}{texExt}"), texFormat);
                }

                break;

            case PsbLinkOrderBy.Order:
                for (var i = 0; i < texs.Count; i++)
                {
                    var tex = texs[i];
                    tex.Save(Path.Combine(dirPath, $"{i}{texExt}"), texFormat);
                }

                break;
            }

            return;
        }
Example #10
0
        internal static void OutputResources(PSB psb, FreeMountContext context, string filePath, PsbExtractOption extractOption = PsbExtractOption.Original,
                                             PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true)
        {
            var             name    = Path.GetFileNameWithoutExtension(filePath);
            var             dirPath = Path.Combine(Path.GetDirectoryName(filePath), name);
            PsbResourceJson resx    = new PsbResourceJson(psb, context.Context);

            if (File.Exists(dirPath))
            {
                name    += "-resources";
                dirPath += "-resources";
            }

            if (!Directory.Exists(dirPath)) //ensure there is no file with same name!
            {
                if (psb.Resources.Count != 0)
                {
                    Directory.CreateDirectory(dirPath);
                }
            }

            var resDictionary = psb.TypeHandler.OutputResources(psb, context, name, dirPath, extractOption);

            //MARK: We use `.resx.json` to distinguish from psbtools' `.res.json`
            if (useResx)
            {
                resx.Resources = resDictionary;
                resx.Context   = context.Context;
                File.WriteAllText(Path.ChangeExtension(filePath, ".resx.json"),
                                  JsonConvert.SerializeObject(resx, Formatting.Indented));
            }
            else
            {
                File.WriteAllText(Path.ChangeExtension(filePath, ".res.json"),
                                  JsonConvert.SerializeObject(resDictionary.Values.ToList(), Formatting.Indented));
            }
        }
Example #11
0
 public Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                    PsbExtractOption extractOption = PsbExtractOption.Original)
 {
     return(null);
 }
Example #12
0
 public virtual void Link(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null, PsbLinkOrderBy order = PsbLinkOrderBy.Convention)
 {
     PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order);
 }
Example #13
0
 public virtual Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                            PsbExtractOption extractOption = PsbExtractOption.Original)
 {
     return(PsbResHelper.OutputImageResources(psb, context, name, dirPath, extractOption));
 }
Example #14
0
 public virtual void UnlinkToFile(PSB psb, FreeMountContext context, string name, string dirPath, bool outputUnlinkedPsb = true,
                                  PsbLinkOrderBy order = PsbLinkOrderBy.Name)
 {
     PsbResHelper.UnlinkImagesToFile(psb, context, name, dirPath, outputUnlinkedPsb, order);
 }
Example #15
0
 public virtual void Link(PSB psb, FreeMountContext context, IDictionary <string, string> resPaths, string baseDir = null)
 {
     PsbResHelper.LinkImages(psb, context, resPaths, baseDir);
 }
Example #16
0
        public Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                           PsbExtractOption extractOption = PsbExtractOption.Original)
        {
            var resources = psb.CollectResources <AudioMetadata>();
            Dictionary <string, string> resDictionary = new Dictionary <string, string>();

            if (extractOption == PsbExtractOption.Original)
            {
                for (int i = 0; i < psb.Resources.Count; i++)
                {
                    var relativePath = psb.Resources[i].Index == null ? $"#{i}.raw" : $"{psb.Resources[i].Index}.raw";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.Resources[i].Data);
                    resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}");
                }
            }
            else
            {
                foreach (var resource in resources)
                {
                    if (resource.ChannelList.Count == 1)
                    {
                        var bts          = resource.ChannelList[0].TryToWave(context);
                        var relativePath = resource.GetFileName(resource.ChannelList[0].Extension + resource.ChannelList[0].WaveExtension); //WaveExtension may change after ToWave
                        if (bts != null)
                        {
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts);
                            resDictionary.Add(resource.Name, $"{name}/{relativePath}");
                        }
                    }
                    else if (resource.ChannelList.Count > 1)
                    {
                        if (resource.Pan == PsbAudioPan.LeftRight) //load audio.vag.l.wav & audio.vag.r.wav
                        {
                            var left          = resource.GetLeftChannel();
                            var relativePathL = resource.GetFileName($"{left.Extension}.l{left.WaveExtension}");
                            var btsL          = left.TryToWave(context);
                            if (btsL != null)
                            {
                                File.WriteAllBytes(Path.Combine(dirPath, relativePathL), btsL);
                            }
                            else
                            {
                                relativePathL = resource.GetFileName($"{left.Extension}.l{left.Extension}");
                                File.WriteAllBytes(Path.Combine(dirPath, relativePathL), left.Data.Data);
                                resDictionary.Add(resource.Name, $"{name}/{relativePathL}");
                            }

                            var right         = resource.GetRightChannel();
                            var relativePathR = resource.GetFileName($"{right.Extension}.r{right.WaveExtension}");
                            var btsR          = right.TryToWave(context);
                            if (btsR != null)
                            {
                                File.WriteAllBytes(Path.Combine(dirPath, relativePathR), btsR);
                            }
                            else
                            {
                                relativePathR = resource.GetFileName($"{right.Extension}.r{right.Extension}");
                                File.WriteAllBytes(Path.Combine(dirPath, relativePathR), right.Data.Data);
                                resDictionary.Add(resource.Name, $"{name}/{relativePathR}");
                            }

                            if (btsL != null && btsR != null)
                            {
                                var relativePath = resource.GetFileName($"{left.Extension}{left.WaveExtension}");
                                resDictionary.Add(resource.Name, $"{name}/{relativePath}"); //a virtual file path
                            }
                        }
                        else //not LeftRight
                        {
                            for (var j = 0; j < resource.ChannelList.Count; j++) //load audio.vag.1.wav etc.
                            {
                                var waveChannel = resource.ChannelList[j];
                                if (waveChannel.Data.Index == null)
                                {
                                    Console.WriteLine($"[WARN] Channel {j} is not linked with a Resource.");
                                    continue;
                                }
                                var bts          = waveChannel.TryToWave(context);
                                var noStr        = waveChannel.Data.Index == null ? $".@{j}" : $".#{waveChannel.Data.Index.Value}"; //TODO: handle @ - channel internal No.
                                var relativePath = resource.GetFileName($"{waveChannel.Extension}{noStr}{waveChannel.WaveExtension}");
                                if (bts != null)
                                {
                                    File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts);
                                    resDictionary.Add(resource.Name, $"{name}/{relativePath}");
                                }
                            }
                        }
                    }
                }
            }

            return(resDictionary);
        }
Example #17
0
        public static Dictionary <string, string> OutputImageResources(PSB psb, FreeMountContext context, string name,
                                                                       string dirPath,
                                                                       PsbExtractOption extractOption = PsbExtractOption.Original,
                                                                       PsbImageFormat extractFormat   = PsbImageFormat.png)
        {
            var resources = psb.CollectResources <ImageMetadata>();

            Dictionary <string, string> resDictionary = new Dictionary <string, string>();

            ImageFormat pixelFormat;

            switch (extractFormat)
            {
            case PsbImageFormat.png:
                pixelFormat = ImageFormat.Png;
                break;

            default:
                pixelFormat = ImageFormat.Bmp;
                break;
            }

            if (extractOption == PsbExtractOption.Original)
            {
                for (int i = 0; i < psb.Resources.Count; i++)
                {
                    var relativePath = psb.Resources[i].Index == null ? $"#{Consts.ResourceIdentifierChar}{i}.bin" : $"{psb.Resources[i].Index}.bin";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.Resources[i].Data);
                    resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}");
                }
            }
            else
            {
                for (int i = 0; i < resources.Count; i++)
                {
                    var resource = resources[i];
                    //Generate Friendly Name
                    var    friendlyName = resource.GetFriendlyName(psb.Type);
                    string relativePath = friendlyName;
                    if (string.IsNullOrWhiteSpace(friendlyName))
                    {
                        relativePath = resource.Resource.Index?.ToString() ?? $"({i})";
                        friendlyName = i.ToString();
                    }

                    var currentExtractOption = extractOption;
                    if (resource.Compress != PsbCompressType.Tlg && resource.Compress != PsbCompressType.ByName && (resource.Width <= 0 || resource.Height <= 0)) //impossible to extract, just keep raw
                    {
                        if (currentExtractOption == PsbExtractOption.Extract)
                        {
                            currentExtractOption = PsbExtractOption.Original;
                        }
                    }

                    switch (currentExtractOption)
                    {
                    case PsbExtractOption.Extract:
                        switch (extractFormat)
                        {
                        case PsbImageFormat.png:
                            relativePath += ".png";
                            break;

                        default:
                            relativePath += ".bmp";
                            break;
                        }

                        relativePath = CheckPath(relativePath, i);
                        if (resource.Compress == PsbCompressType.RL)
                        {
                            RL.DecompressToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                     resource.Height, resource.Width, extractFormat, resource.PixelFormat);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg ||
                                 resource.Compress == PsbCompressType.ByName)
                        {
                            var bmp = context.ResourceToBitmap(resource.Compress == PsbCompressType.Tlg
                                    ? ".tlg"
                                    : Path.GetExtension(resource.Name), resource.Data);
                            if (bmp == null)
                            {
                                if (resource.Compress == PsbCompressType.Tlg)     //Fallback to managed TLG decoder
                                {
                                    using var ms = new MemoryStream(resource.Data);
                                    using var br = new BinaryReader(ms);
                                    bmp          = new TlgImageConverter().Read(br);
                                    bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                    bmp.Dispose();
                                }

                                relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                                File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                            }
                            else
                            {
                                bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                bmp.Dispose();
                            }
                        }
                        //else if (resource.Compress == PsbCompressType.ByName)
                        //{
                        //    relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                        //    File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        //}
                        else
                        {
                            RL.ConvertToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                  resource.Height, resource.Width, extractFormat, resource.PixelFormat, resource.PalData,
                                                  resource.PalettePixelFormat);
                        }

                        break;

                    case PsbExtractOption.Original:
                        if (resources[i].Compress == PsbCompressType.RL)
                        {
                            relativePath += ".rl";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg)
                        {
                            relativePath += ".tlg";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else
                        {
                            relativePath += ".raw";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }

                        break;

                    //case PsbExtractOption.Decompress:
                    //    relativePath += ".raw";
                    //    relativePath = CheckPath(relativePath, i);
                    //    File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                    //        resources[i].Compress == PsbCompressType.RL
                    //            ? RL.Decompress(resource.Data)
                    //            : resource.Data);
                    //    break;
                    //case PsbExtractOption.Compress:
                    //    relativePath += ".rl";
                    //    relativePath = CheckPath(relativePath, i);
                    //    File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                    //        resources[i].Compress != PsbCompressType.RL
                    //            ? RL.Compress(resource.Data)
                    //            : resource.Data);
                    //    break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(currentExtractOption), currentExtractOption, null);
                    }

                    //Determine save name
                    try
                    {
                        bool indexConflict   = false;
                        uint conflictedIndex = 0;
                        if (resource.Resource.Index != null)                          //try index as name first
                        {
                            if (resDictionary.ContainsKey(resource.Index.ToString())) //index is used before
                            {
                                Console.WriteLine(
                                    $"[WARN] Resource Index {resource.Index} conflict. May be resource sharing, but may also be something wrong.");
                                //continue;
                                indexConflict           = true;
                                conflictedIndex         = resource.Resource.Index.Value;
                                resource.Resource.Index = null; //have another try on friendly name
                            }
                        }
                        if (resource.Resource.Index == null)
                        {
                            if (resDictionary.ContainsKey(friendlyName)) // friendly name is also used (most likely its the same res reused), no name can be used to save
                            {
                                Console.WriteLine(
                                    $"[WARN] Resource Name {friendlyName} conflict. May be resource sharing, but may also be something wrong.");
                                continue; //just skip
                            }

                            if (indexConflict) //index is used but friendly name is not (maybe they are different?), save using friendly name
                            {
                                Console.WriteLine($"[FIXED] Resource {friendlyName} is sharing same data with Index {conflictedIndex}");
                            }
                        }

                        resDictionary.Add(resource.Resource.Index == null ? friendlyName : resource.Index.ToString(),
                                          $"{name}/{relativePath}");
                    }
                    catch (ArgumentException e)
                    {
                        throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                        "Resource Export Error: Name conflict, or Index is not specified. Try Raw export mode.", e);
                    }
                }
            }

            string CheckPath(string rPath, int id)
            {
                var k = Path.GetFileNameWithoutExtension(rPath);

                if (resDictionary.ContainsKey(k))
                {
                    return($"{id}{Path.GetExtension(rPath)}");
                }

                return(rPath);
            }

            return(resDictionary);
        }
Example #18
0
 internal static bool UseFlattenArray(this FreeMountContext context)
 {
     return(context.Context.ContainsKey(Consts.Context_UseFlattenArray) && context.Context[Consts.Context_UseFlattenArray] is bool use && use == true);
 }
Example #19
0
 public void Link(PSB psb, FreeMountContext context, IDictionary <string, string> resPaths, string baseDir = null)
 {
 }
Example #20
0
        public static Dictionary <string, string> OutputExtraResources(PSB psb, FreeMountContext context, string name,
                                                                       string dirPath, out Dictionary <string, float[]> flattenArrays, PsbExtractOption extractOption = PsbExtractOption.Original)
        {
            Dictionary <string, string> extraResDictionary = new Dictionary <string, string>();

            flattenArrays = null;

            if (!context.UseFlattenArray() && !Consts.FlattenArrayByDefault)
            {
                extractOption = PsbExtractOption.Original;
            }

            if (extractOption == PsbExtractOption.Original)
            {
                if (!Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }

                for (int i = 0; i < psb.ExtraResources.Count; i++)
                {
                    var relativePath = psb.ExtraResources[i].Index == null ? $"#{Consts.ExtraResourceIdentifierChar}{i}.bin" : $"{Consts.ExtraResourceIdentifierChar}{psb.ExtraResources[i].Index}.bin";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.ExtraResources[i].Data);
                    extraResDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{Consts.ExtraResourceFolderName}/{relativePath}");
                }
            }
            else //Extract
            {
                flattenArrays = new Dictionary <string, float[]>();
                //context.Context[Consts.Context_FlattenArray] = flattenArrays;
                for (int i = 0; i < psb.ExtraResources.Count; i++)
                {
                    var relativePath = psb.ExtraResources[i].Index == null ? $"#{Consts.ExtraResourceIdentifierChar}{i}.bin" : $"{Consts.ExtraResourceIdentifierChar}{psb.ExtraResources[i].Index}.bin";
                    var data         = psb.ExtraResources[i].Data;
                    var resName      = Path.GetFileNameWithoutExtension(relativePath);
                    if (data.Length % 4 == 0)
                    {
                        var floats = MemoryMarshal.Cast <byte, float>(data.AsSpan());
                        flattenArrays.Add(resName, floats.ToArray());
                        //extraResDictionary.Add(resName, "");
                    }
                    else
                    {
                        if (!Directory.Exists(dirPath))
                        {
                            Directory.CreateDirectory(dirPath);
                        }

                        File.WriteAllBytes(
                            Path.Combine(dirPath, relativePath),
                            psb.ExtraResources[i].Data);
                        extraResDictionary.Add(resName, $"{name}/{Consts.ExtraResourceFolderName}/{relativePath}");
                    }
                }
            }

            return(extraResDictionary);
        }
Example #21
0
 public override void Link(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null,
                           PsbLinkOrderBy order = PsbLinkOrderBy.Convention)
 {
     LinkImages(psb, context, resPaths, baseDir, order, true);
 }
Example #22
0
        internal static byte[] LoadImageBytes(string path, ResourceMetadata metadata, FreeMountContext context)
        {
            byte[] data;
            Bitmap image = null;
            var    ext   = Path.GetExtension(path)?.ToLowerInvariant();

            if (metadata.Compress == PsbCompressType.ByName && ext != null && metadata.Name != null &&
                metadata.Name.EndsWith(ext, true, null))
            {
                return(File.ReadAllBytes(path));
            }

            switch (ext)
            {
            //tlg
            case ".tlg" when metadata.Compress == PsbCompressType.Tlg:
                return(File.ReadAllBytes(path));

            case ".tlg":
                image = context.ResourceToBitmap(".tlg", File.ReadAllBytes(path));
                break;

            //rl
            case ".rl" when metadata.Compress == PsbCompressType.RL:
                return(File.ReadAllBytes(path));

            case ".rl" when metadata.Compress == PsbCompressType.None:
                return(RL.Decompress(File.ReadAllBytes(path)));

            case ".rl":
                image = RL.DecompressToImage(File.ReadAllBytes(path), metadata.Height, metadata.Width,
                                             metadata.PixelFormat);
                break;

            //raw
            case ".raw" when metadata.Compress == PsbCompressType.None:
                return(File.ReadAllBytes(path));

            case ".raw" when metadata.Compress == PsbCompressType.RL:
                return(RL.Compress(File.ReadAllBytes(path)));

            case ".raw":
                image = RL.ConvertToImage(File.ReadAllBytes(path), metadata.Height, metadata.Width,
                                          metadata.PixelFormat);
                break;

            //bin
            case ".bin":
                return(File.ReadAllBytes(path));

            //image
            default:
                if (SupportedImageExt.Contains(ext))
                {
                    image = new Bitmap(path);
                }
                else if (context.SupportImageExt(ext))
                {
                    image = context.ResourceToBitmap(ext, File.ReadAllBytes(path));
                }
                else
                {
                    //MARK: No longer try to read files we don't know
                    //return File.ReadAllBytes(path);
                    return(null);
                }

                break;
            }

            switch (metadata.Compress)
            {
            case PsbCompressType.RL:
                data = RL.CompressImage(image, metadata.PixelFormat);
                break;

            case PsbCompressType.Tlg:
                data = context.BitmapToResource(".tlg", image);
                if (data == null)
                {
                    var tlgPath = Path.ChangeExtension(path, ".tlg");
                    if (File.Exists(tlgPath))
                    {
                        Console.WriteLine($"[WARN] Can not encode TLG, using {tlgPath}");
                        data = File.ReadAllBytes(tlgPath);
                    }
                    else
                    {
                        Console.WriteLine($"[WARN] Can not convert image to TLG: {path}");
                        data = File.ReadAllBytes(path);
                    }
                }

                break;

            case PsbCompressType.ByName:
                var imgExt = Path.GetExtension(metadata.Name);
                if (context.SupportImageExt(imgExt))
                {
                    data = context.BitmapToResource(imgExt, image);
                }
                else
                {
                    Console.WriteLine($"[WARN] Unsupported image: {path}");
                    data = File.ReadAllBytes(path);
                }

                break;

            case PsbCompressType.None:
            default:
                data = RL.GetPixelBytesFromImage(image, metadata.PixelFormat);
                break;
            }

            return(data);
        }
Example #23
0
        internal AudioMetadata GenerateAudioMetadata(PSB psb, string name, PsbDictionary voice, FreeMountContext context)
        {
            var md = new AudioMetadata {
                Name = name
            };

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

            if (voice["loopstr"] is PsbString loopstr) //Another bad design. channel[L]ist vs loop[s]tr. WTF M2??
            {
                md.LoopStr = loopstr;
            }
            else if (voice["loopStr"] is PsbString loopStr)
            {
                md.LoopStr = loopStr;
            }

            if (md.LoopStr != null)
            {
                context.Context["loopstr"] = md.LoopStr.Value;
            }

            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);
        }
Example #24
0
        public static void LinkExtraResources(PSB psb, FreeMountContext context, Dictionary <string, string> extraResourcesDictionary, Dictionary <string, float[]> flattenArrays = null, string baseDir = null)
        {
            foreach (var extraResource in psb.ExtraResources)
            {
                if (extraResource.Index == null)
                {
                    Console.WriteLine("[WARN] Found Extra resource without index. Skipped.");
                    continue;
                }
                var key = $"{Consts.ExtraResourceIdentifierChar}{extraResource.Index}";
                if (flattenArrays != null && (context.UseFlattenArray() || Consts.FlattenArrayByDefault))
                {
                    if (!LinkFromFlattenArray(extraResource, key))
                    {
                        if (!LinkFromFile(extraResource, key))
                        {
                            Console.WriteLine($"[WARN] Extra resource {key} cannot be linked.");
                        }
                    }
                }
                else
                {
                    if (!LinkFromFile(extraResource, key))
                    {
                        Console.WriteLine($"[WARN] Extra resource {key} cannot be linked.");
                    }
                }
            }

            bool LinkFromFile(PsbResource res, string key)
            {
                if (extraResourcesDictionary.ContainsKey(key) && !string.IsNullOrEmpty(extraResourcesDictionary[key]))
                {
                    var path     = extraResourcesDictionary[key];
                    var fullPath = Path.IsPathRooted(path)
                        ? path
                        : Path.Combine(baseDir ?? "", path.Replace('/', '\\'));
                    if (!File.Exists(fullPath))
                    {
                        return(false);
                    }
                    res.Data = File.ReadAllBytes(fullPath);
                    return(true);
                }

                return(false);
            }

            bool LinkFromFlattenArray(PsbResource res, string key)
            {
                if (flattenArrays.ContainsKey(key))
                {
                    var floats = flattenArrays[key].AsSpan();
                    var bytes  = MemoryMarshal.Cast <float, byte>(floats);
                    res.Data = bytes.ToArray();
                    return(true);
                }

                return(false);
            }
        }
Example #25
0
 internal static void SetUseFlattenArray(this FreeMountContext context, bool use)
 {
     context.Context[Consts.Context_UseFlattenArray] = use;
 }
Example #26
0
        internal static void OutputResources(PSB psb, FreeMountContext context, string filePath, PsbExtractOption extractOption = PsbExtractOption.Original,
                                             PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true)
        {
            var             name    = Path.GetFileNameWithoutExtension(filePath);
            var             dirPath = Path.Combine(Path.GetDirectoryName(filePath), name);
            PsbResourceJson resx    = new PsbResourceJson(psb, context.Context);

            if (File.Exists(dirPath))
            {
                name    += "-resources";
                dirPath += "-resources";
            }

            var extraDir = Path.Combine(dirPath, Consts.ExtraResourceFolderName);

            if (!Directory.Exists(dirPath)) //ensure there is no file with same name!
            {
                if (psb.Resources.Count != 0)
                {
                    Directory.CreateDirectory(dirPath);
                }
            }

            if (psb.ExtraResources.Count > 0)
            {
                var extraDic = PsbResHelper.OutputExtraResources(psb, context, name, extraDir, out var flattenArrays, extractOption);
                resx.ExtraResources = extraDic;
                if (flattenArrays != null && flattenArrays.Count > 0)
                {
                    resx.ExtraFlattenArrays = flattenArrays;
                }
            }

            var resDictionary = psb.TypeHandler.OutputResources(psb, context, name, dirPath, extractOption);

            //MARK: We use `.resx.json` to distinguish from psbtools' `.res.json`
            if (useResx)
            {
                resx.Resources = resDictionary;
                resx.Context   = context.Context;
                string json;
                if (Consts.JsonArrayCollapse)
                {
                    json = ArrayCollapseJsonTextWriter.SerializeObject(resx);
                }
                else
                {
                    json = JsonConvert.SerializeObject(resx, Formatting.Indented);
                }
                File.WriteAllText(ChangeExtensionForOutputJson(filePath, ".resx.json"), json);
            }
            else
            {
                if (psb.ExtraResources.Count > 0)
                {
                    throw new NotSupportedException("PSBv4 cannot use legacy res.json format.");
                }
                File.WriteAllText(ChangeExtensionForOutputJson(filePath, ".res.json"),
                                  JsonConvert.SerializeObject(resDictionary.Values.ToList(), Formatting.Indented));
            }
        }
Example #27
0
 /// <summary>
 /// Convert <see cref="IArchData"/> to Wave
 /// </summary>
 /// <param name="archData"></param>
 /// <param name="context"></param>
 /// <returns></returns>
 public static byte[] TryToWave(this IArchData archData, FreeMountContext context)
 {
     return(context?.ArchDataToWave(archData.Extension, archData));
 }
Example #28
0
 public void UnlinkToFile(PSB psb, FreeMountContext context, string name, string dirPath, bool outputUnlinkedPsb = true,
                          PsbLinkOrderBy order = PsbLinkOrderBy.Name)
 {
     //TODO:
 }
Example #29
0
        public static void LinkImages(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null,
                                      PsbLinkOrderBy order = PsbLinkOrderBy.Convention, bool isExternal = false)
        {
            if (isExternal)
            {
                MotionType.MotionResourceInstrument(psb);
            }

            var rawResList = psb.CollectResources <ImageMetadata>();

            if (order == PsbLinkOrderBy.Order)
            {
                for (int i = 0; i < rawResList.Count; i++)
                {
                    var resMd    = rawResList[i];
                    var fullPath = Path.Combine(baseDir ?? "", resPaths[i]);
                    resMd.Link(fullPath, context);
                }

                return;
            }

            var resList = rawResList.ToList();

            if (order == PsbLinkOrderBy.Name)
            {
                if (psb.Platform == PsbSpec.krkr)
                {
                    throw new InvalidOperationException(
                              $"Can not link by file name for krkr PSB. Please consider using {PsbLinkOrderBy.Convention}");
                }

                resList.Sort((md1, md2) =>
                             (int)(((ImageMetadata)md1).TextureIndex ?? 0) - (int)(((ImageMetadata)md2).TextureIndex ?? 0));
            }

            for (var i = 0; i < resPaths.Count; i++)
            {
                var resPath = resPaths[i];
                var resName = Path.GetFileNameWithoutExtension(resPath);
                //var resMd = uint.TryParse(resName, out uint rid)
                //    ? resList.FirstOrDefault(r => r.Index == rid)
                //    : resList.FirstOrDefault(r =>
                //        resName == $"{r.Part}{PsbResCollector.ResourceNameDelimiter}{r.Name}");

                //Scan for Resource
                ImageMetadata resMd = null;
                if (order == PsbLinkOrderBy.Name)
                {
                    if (resName == null)
                    {
                        continue;
                    }

                    if (resList.Count == 1 && resPaths.Count == 1)
                    {
                        //If there is only one resource and one texture, we won't care about file name.
                        resMd = resList[0];
                    }
                    else
                    {
                        var texIdx = ImageMetadata.GetTextureIndex(resName);

                        if (texIdx == null)
                        {
                            Console.WriteLine($"[WARN]{resPath} is not used since the file name cannot be recognized.");
                            continue;
                        }

                        if (resList.Count <= texIdx.Value)
                        {
                            Console.WriteLine($"[WARN]{resPath} is not used since the tex No. is too large.");
                            continue;
                        }

                        resMd = resList[(int)texIdx.Value];
                    }
                }
                else //if (order == PsbLinkOrderBy.Convention)
                {
                    resMd = resList.FirstOrDefault(r =>
                                                   resName == $"{r.Part}{Consts.ResourceNameDelimiter}{r.Name}");
                    if (resMd == null && uint.TryParse(resName, out uint rid))
                    {
                        //This Link has no support for raw palette
                        resMd = resList.FirstOrDefault(r => r.Index == rid);
                    }

                    if (resMd == null && psb.Type == PsbType.Pimg)
                    {
                        resMd = resList.FirstOrDefault(r => resName == Path.GetFileNameWithoutExtension(r.Name));
                    }
                }


                if (resMd == null)
                {
                    Console.WriteLine($"[WARN]{resPath} is not used.");
                    continue;
                }

                var fullPath = Path.Combine(baseDir ?? "", resPath.Replace('/', '\\'));
                resMd.Link(fullPath, context);
            }
        }
Example #30
0
        internal static void OutputResources(PSB psb, FreeMountContext context, string filePath, PsbImageOption imageOption = PsbImageOption.Original,
                                             PsbImageFormat extractFormat = PsbImageFormat.Png, bool useResx = true)
        {
            var name    = Path.GetFileNameWithoutExtension(filePath);
            var dirPath = Path.Combine(Path.GetDirectoryName(filePath), name);

            var             resources = psb.CollectResources();
            PsbResourceJson resx      = new PsbResourceJson(psb, context.Context);

            if (File.Exists(dirPath))
            {
                name    += "-resources";
                dirPath += "-resources";
            }

            if (!Directory.Exists(dirPath)) //ensure there is no file with same name!
            {
                if (psb.Resources.Count != 0 || resources.Count != 0)
                {
                    Directory.CreateDirectory(dirPath);
                }
            }

            Dictionary <string, string> resDictionary = new Dictionary <string, string>();

            if (imageOption == PsbImageOption.Original)
            {
                for (int i = 0; i < psb.Resources.Count; i++)
                {
                    var relativePath = psb.Resources[i].Index == null ? $"#{i}.bin" : $"{psb.Resources[i].Index}.bin";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.Resources[i].Data);
                    resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}");
                }
            }
            else
            {
                for (int i = 0; i < resources.Count; i++)
                {
                    var resource = resources[i];
                    //Generate Friendly Name
                    string relativePath = resource.GetFriendlyName(psb.Type);

                    switch (imageOption)
                    {
                    case PsbImageOption.Extract:
                        ImageFormat pixelFormat;
                        switch (extractFormat)
                        {
                        case PsbImageFormat.Png:
                            relativePath += ".png";
                            pixelFormat   = ImageFormat.Png;
                            break;

                        default:
                            relativePath += ".bmp";
                            pixelFormat   = ImageFormat.Bmp;
                            break;
                        }

                        relativePath = CheckPath(relativePath, i);
                        if (resource.Compress == PsbCompressType.RL)
                        {
                            RL.DecompressToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                     resource.Height, resource.Width, extractFormat, resource.PixelFormat);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg ||
                                 resource.Compress == PsbCompressType.ByName)
                        {
                            var bmp = context.ResourceToBitmap(resource.Compress == PsbCompressType.Tlg
                                    ? ".tlg"
                                    : Path.GetExtension(resource.Name), resource.Data);
                            if (bmp == null)
                            {
                                if (resource.Compress == PsbCompressType.Tlg)     //Fallback to managed TLG decoder
                                {
                                    using (var ms = new MemoryStream(resource.Data))
                                        using (var br = new BinaryReader(ms))
                                        {
                                            bmp = new TlgImageConverter().Read(br);
                                            bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                            bmp.Dispose();
                                        }
                                }

                                relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                                File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                            }
                            else
                            {
                                bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                bmp.Dispose();
                            }
                        }
                        //else if (resource.Compress == PsbCompressType.ByName)
                        //{
                        //    relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                        //    File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        //}
                        else
                        {
                            RL.ConvertToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                  resource.Height, resource.Width, extractFormat, resource.PixelFormat);
                        }

                        break;

                    case PsbImageOption.Original:
                        if (resources[i].Compress == PsbCompressType.RL)
                        {
                            relativePath += ".rl";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg)
                        {
                            relativePath += ".tlg";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else
                        {
                            relativePath += ".raw";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }

                        break;

                    case PsbImageOption.Decompress:
                        relativePath += ".raw";
                        relativePath  = CheckPath(relativePath, i);
                        File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                                           resources[i].Compress == PsbCompressType.RL
                                    ? RL.Decompress(resource.Data)
                                    : resource.Data);
                        break;

                    case PsbImageOption.Compress:
                        relativePath += ".rl";
                        relativePath  = CheckPath(relativePath, i);
                        File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                                           resources[i].Compress != PsbCompressType.RL
                                    ? RL.Compress(resource.Data)
                                    : resource.Data);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(imageOption), imageOption, null);
                    }

                    try
                    {
                        resDictionary.Add(i.ToString(), $"{name}/{relativePath}");
                    }
                    catch (ArgumentException e)
                    {
                        throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                        "There are resources with same names! Try Raw export mode.", e);
                    }
                }
            }

            //MARK: We use `.resx.json` to distinguish from psbtools' `.res.json`
            if (useResx)
            {
                resx.Resources = resDictionary;
                resx.Context   = context.Context;
                File.WriteAllText(Path.ChangeExtension(filePath, ".resx.json"),
                                  JsonConvert.SerializeObject(resx, Formatting.Indented));
            }
            else
            {
                File.WriteAllText(Path.ChangeExtension(filePath, ".res.json"),
                                  JsonConvert.SerializeObject(resDictionary.Values.ToList(), Formatting.Indented));
            }

            string CheckPath(string rPath, int id)
            {
                var k = Path.GetFileNameWithoutExtension(rPath);

                if (resDictionary.ContainsKey(k))
                {
                    return($"{id}{Path.GetExtension(rPath)}");
                }

                return(rPath);
            }
        }