Exemple #1
0
        /// <summary>
        /// 转换 NCM 文件为 Flac/MP3 文件
        /// </summary>
        /// <param name="filePath">NCM 文件路径</param>
        /// <returns>转换状态</returns>
        public NCMConverterEnum ProcessFile(string filePath)
        {
            using (var fs = File.Open(filePath, FileMode.Open))
            {
                // 校验是否是网易云加密的 NCM 文件
                if (NCMExtenstion.ReadInt32(fs) != 0x4e455443)
                {
                    return(NCMConverterEnum.Invalid);
                }

                if (NCMExtenstion.ReadInt32(fs) != 0x4d414446)
                {
                    return(NCMConverterEnum.Invalid);
                }

                // 读取密钥
                NCMExtenstion.Seek(fs, 2);
                var keyBytes = NCMExtenstion.ReadBytes(fs, NCMExtenstion.ReadInt32(fs));

                for (int i = 0; i < keyBytes.Length; i++)
                {
                    keyBytes[i] ^= 0x64;
                }

                // 减去 "neteasecloudmusic" 字符串之后的数据即为密钥数据
                var deKeyDataBytes = NCMExtenstion.GetBytesByOffset(NCMExtenstion.DecryptAes128Ecb(Encoding.UTF8.GetBytes(NCMConveterConsts.AesCoreKeyString), keyBytes), 17);

                var modifyDataBytes = NCMExtenstion.ReadBytes(fs, NCMExtenstion.ReadInt32(fs));
                for (int i = 0; i < modifyDataBytes.Length; i++)
                {
                    modifyDataBytes[i] ^= 0x63;
                }

                var decryptBase64          = SystemConvert.FromBase64String(Encoding.UTF8.GetString(NCMExtenstion.GetBytesByOffset(modifyDataBytes, 22)));
                var decryptModifyDataBytes = NCMExtenstion.DecryptAes128Ecb(Encoding.UTF8.GetBytes(NCMConveterConsts.AesModifyKeyBytes), decryptBase64);

                // 获取 NCM 文件的歌曲文件信息 Json
                var musicJson     = JObject.Parse(Encoding.UTF8.GetString(NCMExtenstion.GetBytesByOffset(decryptModifyDataBytes, 6)));
                var fileExtension = musicJson.SelectToken("$.format").Value <string>();

                // 跳过 CRC 校验
                NCMExtenstion.Seek(fs, 9);

                // 跳过专辑图像数据
                var imageBytes = new byte[NCMExtenstion.ReadInt32(fs)];
                if (imageBytes.Length != 0)
                {
                    fs.Read(imageBytes, 0, imageBytes.Length);
                }

                var box = NCMExtenstion.BuildKeyBox(deKeyDataBytes);

                var n = 0x8000;
                using (var outputFile = File.Create(Path.Combine(Path.GetDirectoryName(filePath), $"{Path.GetFileNameWithoutExtension(filePath)}.{fileExtension}")))
                {
                    while (true)
                    {
                        var tb     = new byte[n];
                        var result = fs.Read(tb, 0, n);
                        if (result <= 0)
                        {
                            break;
                        }

                        for (int i = 0; i < n; i++)
                        {
                            var j = (byte)((i + 1) & 0xff);
                            tb[i] ^= box[box[j] + box[(box[j] + j) & 0xff] & 0xff];
                        }

                        outputFile.Write(tb, 0, n);
                    }

                    outputFile.Flush();
                }

                fs.Close();
                return(NCMConverterEnum.Success);
            }
        }
Exemple #2
0
        object IParser.Parse(XElement e)
        {
            string name;
            object id;

            byte[]       content;
            Entity       entity;
            bool         templateByDefault;
            EnumTreeType treeType;

            ParseObject(e, out id, out name);

            var fileNameAttribute = e.Attribute("fileName");

            if (fileNameAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "fileName", e), "e");
            }

            var typeNameAttribute = e.Attribute("typeName");

            if (typeNameAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "typeName", e), "e");
            }

            var typeCodeAttribute = e.Attribute("typeCode");

            if (typeCodeAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "typeCode", e), "e");
            }

            var entityIDAttribute = e.Attribute("entityID");

            if (entityIDAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "entityID", e), "e");
            }

            entity = Storage.Select <Entity>(entityIDAttribute.Value);

            var templateByDefaultAttribute = e.Attribute("templateByDefault");

            if (templateByDefaultAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "entityID", e), "e");
            }

            templateByDefault = templateByDefaultAttribute.Value == "1" ? true : false;


            var treeTypeIDAttribute = e.Attribute("templateByDefault");

            if (treeTypeIDAttribute == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoAttribute", "entityID", e), "e");
            }

            treeType = GetTreeTypeID(e.Attribute("treeTypeID").Value);

            List <TemplateField> fields = new List <TemplateField>();

            var fieldsElement = e.Element("fields");

            if (fieldsElement != null)
            {
                var fieldElements = fieldsElement.Elements("field");

                if (fieldElements.Count() == 0)
                {
                    throw new ArgumentException(Message.Get("Xml.NoElements", "field", e), "e");
                }

                templateFieldParser = new TemplateFieldParser(entity);



                fields = fieldElements.Select(o => templateFieldParser.Parse(o)).ToList();
            }

            var contentNode = e.Element("content");

            if (contentNode == null)
            {
                throw new ArgumentException(Message.Get("Xml.NoElement", "content", e), "content");
            }

            try
            {
                content = Convert.FromBase64String(contentNode.Value);
            }
            catch
            {
#warning Использую ArithmeticException.
                throw new ArithmeticException("Не удалось преобразовать тело документа к массиву байт.");
            }

            var sheetAttribute = e.Attribute("sheet");
            Dictionary <string, string> parameters = null;

            if (sheetAttribute != null)
            {
                parameters          = new System.Collections.Generic.Dictionary <string, string>();
                parameters["sheet"] = sheetAttribute.Value;
            }

            return(new Template(id, name, entity, fileNameAttribute.Value, typeNameAttribute.Value, typeCodeAttribute.Value, templateByDefault, treeType, content, fields, parameters));
        }