✨ Parse manifest.xml into JSON
This commit is contained in:
parent
77e039901a
commit
82804f6657
3 changed files with 51 additions and 21 deletions
|
@ -2,6 +2,7 @@ import { TextDecoder } from 'util';
|
||||||
import * as xmlJs from 'xml-js';
|
import * as xmlJs from 'xml-js';
|
||||||
import getUrlContents from '../cdn/getUrlContents';
|
import getUrlContents from '../cdn/getUrlContents';
|
||||||
import { Product } from '../interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
|
import parsePatchmanifest from '../ssn/parsePatchmanifest';
|
||||||
import verifyPatchmanifest from '../ssn/verifyPatchmanifest';
|
import verifyPatchmanifest from '../ssn/verifyPatchmanifest';
|
||||||
import verifyProductName from '../ssn/verifyProductName';
|
import verifyProductName from '../ssn/verifyProductName';
|
||||||
import extractFile from './extractFile';
|
import extractFile from './extractFile';
|
||||||
|
@ -21,6 +22,7 @@ export default async function getPatchmanifest(product: Product): Promise<any> {
|
||||||
//Parse .patchmanifest file
|
//Parse .patchmanifest file
|
||||||
const fileEntries = readSsnFile(ssnFile);
|
const fileEntries = readSsnFile(ssnFile);
|
||||||
|
|
||||||
|
//Verify .patchmanifest file
|
||||||
if (fileEntries.length !== 1) {
|
if (fileEntries.length !== 1) {
|
||||||
throw new Error(`Expected .patchmanifest to contain 1 file but it had "${fileEntries.length}" files.`);
|
throw new Error(`Expected .patchmanifest to contain 1 file but it had "${fileEntries.length}" files.`);
|
||||||
}
|
}
|
||||||
|
@ -32,10 +34,18 @@ export default async function getPatchmanifest(product: Product): Promise<any> {
|
||||||
|
|
||||||
//Extract manifest.xml file
|
//Extract manifest.xml file
|
||||||
const patchmanifestFile = await extractFile(firstFile, [new DataView(ssnFile)]);
|
const patchmanifestFile = await extractFile(firstFile, [new DataView(ssnFile)]);
|
||||||
|
|
||||||
|
//Convert ArrayBuffer to string
|
||||||
const patchmanifestXml = Decoder.decode(patchmanifestFile);
|
const patchmanifestXml = Decoder.decode(patchmanifestFile);
|
||||||
|
|
||||||
|
//convert XML to JSON-converted XML
|
||||||
const patchManifestJson = xmlJs.xml2js(patchmanifestXml) as xmlJs.Element;
|
const patchManifestJson = xmlJs.xml2js(patchmanifestXml) as xmlJs.Element;
|
||||||
|
|
||||||
|
//verify that XML file contains all required elements and attributes
|
||||||
verifyPatchmanifest(patchManifestJson, product);
|
verifyPatchmanifest(patchManifestJson, product);
|
||||||
|
|
||||||
return patchManifestJson;
|
//convert JSON-converted XML to an easier to read JSON
|
||||||
|
const patchManifestSimple = parsePatchmanifest(patchManifestJson);
|
||||||
|
|
||||||
|
return patchManifestSimple;
|
||||||
}
|
}
|
||||||
|
|
20
src/ssn/parsePatchmanifest.ts
Normal file
20
src/ssn/parsePatchmanifest.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
/** Receives a JSON-converted version of the manifest.xml file, and returns an easier to read JSON file */
|
||||||
|
export default function parsePatchManifest(manifestFile: any): any {
|
||||||
|
const out: any = {};
|
||||||
|
|
||||||
|
const PatchManifest = manifestFile.elements[0];
|
||||||
|
|
||||||
|
//<RequiredRelease>289</RequiredRelease>
|
||||||
|
const RequiredRelease = PatchManifest.elements[2];
|
||||||
|
out.current = Number(RequiredRelease.elements[0].text);
|
||||||
|
|
||||||
|
//<Releases><Release><Id>0</Id><SHA1>53678f8057e52896a8145dca5c188ab3f24fa55f</SHA1></Release></Releases>
|
||||||
|
const Releases = PatchManifest.elements[7];
|
||||||
|
out.releases = Releases.elements.map((Release: any) => ({ id: Release.elements[0].elements[0].text, sha1: Release.elements[1].elements[0].text }));
|
||||||
|
|
||||||
|
const ReleaseUpdatePaths = PatchManifest.elements[8];
|
||||||
|
out.paths = ReleaseUpdatePaths.elements.map((ReleaseUpdatePath: any) => ({ from: ReleaseUpdatePath.elements[0].elements[0].text, to: ReleaseUpdatePath.elements[1].elements[0].text }));
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
|
@ -1,45 +1,45 @@
|
||||||
import * as xmlJs from 'xml-js';
|
import * as xmlJs from 'xml-js';
|
||||||
import { Product } from '../interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
|
|
||||||
/** Receives a JSON-converted version of the manifest.xml file */
|
/** Receives a JSON-converted version of the manifest.xml file, and verifies that all required elements and attributes are present, and nothing more */
|
||||||
export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product): any {
|
export default function verifyPatchmanifest(manifestFile: xmlJs.Element, product: Product): any {
|
||||||
//<?xml version="1.0" encoding="utf-8"?>
|
//<?xml version="1.0" encoding="utf-8"?>
|
||||||
if (obj.declaration === undefined || obj.declaration.attributes === undefined || Object.keys(obj.declaration.attributes).length !== 2 || obj.declaration.attributes.version !== '1.0' || obj.declaration.attributes.encoding !== 'utf-8') {
|
if (manifestFile.declaration === undefined || manifestFile.declaration.attributes === undefined || Object.keys(manifestFile.declaration.attributes).length !== 2 || manifestFile.declaration.attributes.version !== '1.0' || manifestFile.declaration.attributes.encoding !== 'utf-8') {
|
||||||
throw new Error('Expected declration with version 1.0 and utf-8 encoding.');
|
throw new Error('Expected declration with version 1.0 and utf-8 encoding.');
|
||||||
}
|
}
|
||||||
|
|
||||||
//<PatchManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
//<PatchManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
if (obj.elements === undefined || obj.elements.length !== 1) {
|
if (manifestFile.elements === undefined || manifestFile.elements.length !== 1) {
|
||||||
throw new Error('Expected one root element.');
|
throw new Error('Expected one root element.');
|
||||||
}
|
}
|
||||||
const root = obj.elements[0];
|
const PatchManifest = manifestFile.elements[0];
|
||||||
if (root.type !== 'element' || root.name !== 'PatchManifest') {
|
if (PatchManifest.type !== 'element' || PatchManifest.name !== 'PatchManifest') {
|
||||||
throw new Error(`Expected root element to be called PatchManifest but it was "${root.name}".`);
|
throw new Error(`Expected root element to be called PatchManifest but it was "${PatchManifest.name}".`);
|
||||||
}
|
}
|
||||||
if (root.attributes === undefined || Object.keys(root.attributes).length !== 2 || root.attributes['xmlns:xsi'] !== 'http://www.w3.org/2001/XMLSchema-instance' || root.attributes['xmlns:xsd'] !== 'http://www.w3.org/2001/XMLSchema') {
|
if (PatchManifest.attributes === undefined || Object.keys(PatchManifest.attributes).length !== 2 || PatchManifest.attributes['xmlns:xsi'] !== 'http://www.w3.org/2001/XMLSchema-instance' || PatchManifest.attributes['xmlns:xsd'] !== 'http://www.w3.org/2001/XMLSchema') {
|
||||||
throw new Error(`Expected root element to have attributes xmlns:xsi and xmlns:xsd.`);
|
throw new Error(`Expected root element to have attributes xmlns:xsi and xmlns:xsd.`);
|
||||||
}
|
}
|
||||||
if (root.elements === undefined) {
|
if (PatchManifest.elements === undefined) {
|
||||||
throw new Error(`Expected child elements under PatchManifest but there were none.`);
|
throw new Error(`Expected child elements under PatchManifest but there were none.`);
|
||||||
}
|
}
|
||||||
if (root.elements.length !== 9) {
|
if (PatchManifest.elements.length !== 9) {
|
||||||
throw new Error(`Expected 9 child elements under PatchManifest but there were ${root.elements.length}.`);
|
throw new Error(`Expected 9 child elements under PatchManifest but there were ${PatchManifest.elements.length}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//<Dependencies />
|
//<Dependencies />
|
||||||
const Dependencies = root.elements[0];
|
const Dependencies = PatchManifest.elements[0];
|
||||||
if (Dependencies.type !== 'element' || Dependencies.name !== 'Dependencies' || Dependencies.attributes !== undefined || Dependencies.elements !== undefined) {
|
if (Dependencies.type !== 'element' || Dependencies.name !== 'Dependencies' || Dependencies.attributes !== undefined || Dependencies.elements !== undefined) {
|
||||||
throw new Error('Expected Dependencies element with no child elements and no attributes.');
|
throw new Error('Expected Dependencies element with no child elements and no attributes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
//<Name>assets_swtor_de_de</Name>
|
//<Name>assets_swtor_de_de</Name>
|
||||||
const Name = root.elements[1];
|
const Name = PatchManifest.elements[1];
|
||||||
if (Name.type !== 'element' || Name.name !== 'Name' || Name.attributes !== undefined || Name.elements === undefined || Name.elements.length !== 1 || Name.elements[0].type !== 'text' || Name.elements[0].text !== product) {
|
if (Name.type !== 'element' || Name.name !== 'Name' || Name.attributes !== undefined || Name.elements === undefined || Name.elements.length !== 1 || Name.elements[0].type !== 'text' || Name.elements[0].text !== product) {
|
||||||
throw new Error('Expected Name element with one child element equal to product and no attributes.');
|
throw new Error('Expected Name element with one child element equal to product and no attributes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
//<RequiredRelease>289</RequiredRelease>
|
//<RequiredRelease>289</RequiredRelease>
|
||||||
const RequiredRelease = root.elements[2];
|
const RequiredRelease = PatchManifest.elements[2];
|
||||||
if (RequiredRelease.type !== 'element' || RequiredRelease.name !== 'RequiredRelease' || RequiredRelease.attributes !== undefined || RequiredRelease.elements === undefined) {
|
if (RequiredRelease.type !== 'element' || RequiredRelease.name !== 'RequiredRelease' || RequiredRelease.attributes !== undefined || RequiredRelease.elements === undefined) {
|
||||||
throw new Error('Expected RequiredRelease element.');
|
throw new Error('Expected RequiredRelease element.');
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<UpcomingRelease>-1</UpcomingRelease>
|
//<UpcomingRelease>-1</UpcomingRelease>
|
||||||
const UpcomingRelease = root.elements[3];
|
const UpcomingRelease = PatchManifest.elements[3];
|
||||||
if (UpcomingRelease.type !== 'element' || UpcomingRelease.name !== 'UpcomingRelease' || UpcomingRelease.attributes !== undefined || UpcomingRelease.elements === undefined) {
|
if (UpcomingRelease.type !== 'element' || UpcomingRelease.name !== 'UpcomingRelease' || UpcomingRelease.attributes !== undefined || UpcomingRelease.elements === undefined) {
|
||||||
throw new Error('Expected UpcomingRelease element.');
|
throw new Error('Expected UpcomingRelease element.');
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<TargetDirectory>{ModulePath}</TargetDirectory>
|
//<TargetDirectory>{ModulePath}</TargetDirectory>
|
||||||
const TargetDirectory = root.elements[4];
|
const TargetDirectory = PatchManifest.elements[4];
|
||||||
if (TargetDirectory.type !== 'element' || TargetDirectory.name !== 'TargetDirectory' || TargetDirectory.attributes !== undefined || TargetDirectory.elements === undefined) {
|
if (TargetDirectory.type !== 'element' || TargetDirectory.name !== 'TargetDirectory' || TargetDirectory.attributes !== undefined || TargetDirectory.elements === undefined) {
|
||||||
throw new Error('Expected TargetDirectory element.');
|
throw new Error('Expected TargetDirectory element.');
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<RequiresElevation>false</RequiresElevation>
|
//<RequiresElevation>false</RequiresElevation>
|
||||||
const RequiresElevation = root.elements[5];
|
const RequiresElevation = PatchManifest.elements[5];
|
||||||
if (RequiresElevation.type !== 'element' || RequiresElevation.name !== 'RequiresElevation' || RequiresElevation.attributes !== undefined || RequiresElevation.elements === undefined) {
|
if (RequiresElevation.type !== 'element' || RequiresElevation.name !== 'RequiresElevation' || RequiresElevation.attributes !== undefined || RequiresElevation.elements === undefined) {
|
||||||
throw new Error('Expected RequiresElevation element.');
|
throw new Error('Expected RequiresElevation element.');
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<Maintenance>false</Maintenance>
|
//<Maintenance>false</Maintenance>
|
||||||
const Maintenance = root.elements[6];
|
const Maintenance = PatchManifest.elements[6];
|
||||||
if (Maintenance.type !== 'element' || Maintenance.name !== 'Maintenance' || Maintenance.attributes !== undefined || Maintenance.elements === undefined) {
|
if (Maintenance.type !== 'element' || Maintenance.name !== 'Maintenance' || Maintenance.attributes !== undefined || Maintenance.elements === undefined) {
|
||||||
throw new Error('Expected Maintenance element.');
|
throw new Error('Expected Maintenance element.');
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<Releases>
|
//<Releases>
|
||||||
const Releases = root.elements[7];
|
const Releases = PatchManifest.elements[7];
|
||||||
if (Releases.type !== 'element' || Releases.name !== 'Releases' || Releases.attributes !== undefined || Releases.elements === undefined) {
|
if (Releases.type !== 'element' || Releases.name !== 'Releases' || Releases.attributes !== undefined || Releases.elements === undefined) {
|
||||||
throw new Error('Expected Releases element.');
|
throw new Error('Expected Releases element.');
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ export default function verifyPatchmanifest(obj: xmlJs.Element, product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
//<ReleaseUpdatePaths>
|
//<ReleaseUpdatePaths>
|
||||||
const ReleaseUpdatePaths = root.elements[8];
|
const ReleaseUpdatePaths = PatchManifest.elements[8];
|
||||||
if (ReleaseUpdatePaths.type !== 'element' || ReleaseUpdatePaths.name !== 'ReleaseUpdatePaths' || ReleaseUpdatePaths.attributes !== undefined || ReleaseUpdatePaths.elements === undefined) {
|
if (ReleaseUpdatePaths.type !== 'element' || ReleaseUpdatePaths.name !== 'ReleaseUpdatePaths' || ReleaseUpdatePaths.attributes !== undefined || ReleaseUpdatePaths.elements === undefined) {
|
||||||
throw new Error('Expected ReleaseUpdatePaths element.');
|
throw new Error('Expected ReleaseUpdatePaths element.');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue