/// <summary>
        /// Load manifest file (MANIFEST.MF) for the specified APK.
        /// </summary>
        /// <param name="pathApkMainDirectory">
        /// Directory with all the APK's files.
        /// </param>
        /// <returns>
        /// APK manifest file with records about file in APK.
        /// Returns NULL if manifest file could not be found.
        /// </returns>
        public static AndroidApplicationManifest GetApplicationManifest(string pathAppPackageDir)
        {
            var manifest = new AndroidApplicationManifest();

            string pathManifest = Path.Combine(pathAppPackageDir, PATH_MANIFEST);

            // Error if MANIFEST.MF can't be found in the APK's main directory
            if (!File.Exists(pathManifest)) return null;

            // We consider the specifics of MANIFEST.MF when we read it
            // MANIFEST.MF consists of records about files in APK
            // Record looks like:
            //     Name: file_name (NOTE: may be on 2 lines)
            //     SHA1-Digest: file_sha1
            using (StreamReader reader = new StreamReader(pathManifest))
            {
                while (!reader.EndOfStream)
                {
                    string input = reader.ReadLine();
                    // Skip empty lines and control information as we are interested only
                    // in records about files
                    if (input.Equals(String.Empty) || !input.StartsWith("Name")) continue;

                    string[] inputParts = input.Split(' ');
                    string fileName;
                    string fileSHA;

                    // Read another line to check that the file's path is presented as one line
                    // If it is one line that it must be followed by SHA1
                    string secondInput = reader.ReadLine().Trim();
                    if (secondInput.StartsWith("SHA"))
                    {
                        fileName = inputParts[1];
                        for (int i = 2; i < inputParts.Length; ++i)
                        {
                            fileName += (" " + inputParts[i]);
                        }
                        fileSHA = secondInput.Split(' ')[1];

                    }
                    // Case when 2 lines are used for the file name
                    // Add combination of lines as the file name
                    else
                    {
                        fileName = inputParts[1];
                        for (int i = 2; i < inputParts.Length; ++i)
                        {
                            fileName += (" " + inputParts[i]);
                        }
                        fileName += secondInput;
                        // SHA is on the next line
                        fileSHA = reader.ReadLine().Split(' ')[1];
                    }

                    // Make all the slashes Windows style
                    FileManager.FixSlashesInPath(ref fileName);

                    manifest.AddFileRecordToManifest(new AndroidApplicationManifestRecord(fileName, fileSHA));
                }
            }

            return manifest;
        }
        /// <summary>
        /// Marks appropriate files in the reference package as UPDATED.
        /// Files marked UPDATED - presented in both the old and the target packages but with different SHAs.
        /// NOTE: Files marked UPDATED will have SHA from the reference package
        /// </summary>
        /// <param name="oldAndroidApplicationManifest">
        /// Manifest file of the reference package.
        /// </param>
        /// <param name="targetManifest">
        /// Manifest file of the target package.
        /// </param>
        /// <returns>
        /// Set of files that are marked UPDATED.
        /// </returns>
        private static HashSet<AndroidApplicationManifestRecord> MarkFilesUPDATED(AndroidApplicationManifest referenceManifest, AndroidApplicationManifest targetManifest)
        {
            // Get the files presented both in the old and the target packages
            HashSet<AndroidApplicationManifestRecord> commonFilesInManifest = new HashSet<AndroidApplicationManifestRecord>(referenceManifest.FilesInPackage);
            commonFilesInManifest.IntersectWith(targetManifest.FilesInPackage);

            HashSet<AndroidApplicationManifestRecord> filesMarkedUpdated = new HashSet<AndroidApplicationManifestRecord>();

            // Go through the files and remove those with that are the same in both manifests
            foreach (AndroidApplicationManifestRecord record in commonFilesInManifest)
            {
                // Get the file's SHA in the target package
                string newFileSHA = targetManifest.FilesInPackage.First(x => x.FileName == record.FileName).FileSHA;
                // Files are marked as SAME if SHAs are the same.
                // Files are marked as UPDATED if SHAs are different.
                if (!record.FileSHA.Equals(newFileSHA))
                {
                    filesMarkedUpdated.Add(record);
                }
            }

            return filesMarkedUpdated;
        }
 /// <summary>
 /// Marks appropriate files in the reference package as DELETE.
 /// Files marked DELETE - presented in the reference package but not in the target package.
 /// </summary>
 /// <param name="referenceManifest">
 /// Manifest file of the reference package.
 /// </param>
 /// <param name="targetManifest">
 /// Manifest file of the target package.
 /// </param>
 /// <returns>
 /// Set of files that are marked DELETE
 /// </returns>
 private static HashSet<AndroidApplicationManifestRecord> MarkFilesDELETE(AndroidApplicationManifest referenceManifest, AndroidApplicationManifest targetManifest)
 {
     HashSet<AndroidApplicationManifestRecord> filesMarkedDelete = new HashSet<AndroidApplicationManifestRecord>(referenceManifest.FilesInPackage);
     filesMarkedDelete.ExceptWith(targetManifest.FilesInPackage);
     return filesMarkedDelete;
 }
 /// <summary>
 /// Marks appropriate files in the target package as NEW.
 /// Files marked NEW - presented in the target package but not in the reference package
 /// </summary>
 /// <param name="referenceManifest">
 /// Manifest file of the reference package.
 /// </param>
 /// <param name="targetManifest">
 /// Manifest file of the target package.
 /// </param>
 /// <returns>
 /// Set of files that are marked NEW.
 /// </returns>
 private static HashSet<AndroidApplicationManifestRecord> MarkFilesNEW(AndroidApplicationManifest referenceManifest, AndroidApplicationManifest targetManifest)
 {
     HashSet<AndroidApplicationManifestRecord> filesMarkedNew = new HashSet<AndroidApplicationManifestRecord>(targetManifest.FilesInPackage);
     filesMarkedNew.ExceptWith(referenceManifest.FilesInPackage);
     return filesMarkedNew;
 }
 public AndroidApplicationManifest(AndroidApplicationManifest appManifest)
 {
     FilesInPackage = new HashSet<AndroidApplicationManifestRecord>(appManifest.FilesInPackage);
 }