Collection was modified; enumeration operation might not execute in LinQ - c#

I get data from a site and insert to DataTable dt.
if (checked = true)
{
while (true)
{
breakIt = true;
try
{
string html = browser_array[idx].FindElementByXPath("id('tabbox')").GetAttribute("outerHTML");
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
HtmlNodeCollection nodesMatchingXPathlop = doc.DocumentNode.SelectNodes("//*[contains(#class,'tabbox_F')]/table/tbody/tr");
if (nodesMatchingXPathlop.Count == 0)
{
break;
}
else
{
for (int j = 0; j < nodesMatchingXPathlop.Count; j++)
{
try
{
listHeader[1].Clear();
HtmlNodeCollection listTD3 = nodesMatchingXPathlop[j].SelectNodes("td");
if (nodesMatchingXPathlop[j].SelectNodes("td").ToString() == "")
return;
if (nodesMatchingXPathlop[j].SelectNodes("td").Count == 10)
{
if (listHeader[1].Count == 0)
continue;
else
Insert(dt, listHeader[1]);
}
else
{
continue;
}
}
catch (Exception ex) { throw; }
}
}
if (breakIt)
{
break;
}
}
catch (Exception ex) { throw; }
}
}
So, this function is Insert(DataTable dt, List<String> listHeader):
static void Insert(DataTable dt, List<String> listHeader)
{
DataRow row = dt.NewRow();
string[] array = listHeader.ToArray();
string newArray = "";
newArray = Regex.Replace(array[1], #"\s+", " ");
string arrayHindiCap2 = "";
arrayHindiCap2 = Regex.Replace(array[2], #"\s+", " ").Replace(" ", "");
string arrayHindiCap5 = "";
arrayHindiCap5 = Regex.Replace(array[5], #"\s+", " ").Replace(" ", "");
try
{
if (!string.IsNullOrWhiteSpace(arrayHindiCap2))
{
InsertCondition(arrayHindiCap2, arrayHindiCap5, newArray, listHeader, array);
}
else if (!string.IsNullOrWhiteSpace(arrayHindiCap5))
{
InsertCondition(arrayHindiCap2, arrayHindiCap5, newArray, listHeader, array);
}
}
catch (Exception ex) { throw; }
}
I have a table like this:
Option B0_1 Col 1 Col 2
op1 10 89
I will get an index of rows in DataTable when it correct with a condition.
static void InsertCondition(string arrayHindiCap2, string arrayHindiCap5, string newArray, List<String> listHeader, string[] array)
{
try
{
index = dt.AsEnumerable()
.Select((rowF, idx) => new { rowF, idx })
.Where(item =>
GetFirstB(numB) == (item.rowF.Field<string>("B0_1") != null ? item.rowF.Field<string>("B0_1") : "") &&
GetFirstWord(optionString) == (item.rowF.Field<string>("Option") != null ? item.rowF.Field<string>("Option") : ""))
.Select(item => item.idx)
.ToArray();
}
catch(Exception ex) { throw; }
}
I define GetFirstB() and GetFirstWord():
private static string GetFirstWord(string str)
{
try
{
return string.Concat(str.Split(' ').Take(2));
}
catch (Exception ex) { throw; }
}
private static string GetFirstB(string str)
{
try
{
if (str == null)
return null;
if (str.Equals(" "))
return null;
string[] strNew;
strNew = str.Split(' ');
strNew = strNew.Where(c => c != "").ToArray();
return string.Concat(strNew.FirstOrDefault());
}
catch (Exception ex) { throw; }
}
Following #ScottChamberlain and #PhilipKendall suggest.
I edit my code and tried debug again.
After Copy exception copies detail to clipboard it shows like this:
System.InvalidOperationException was caught
HResult=-2146233079
Message=Collection was modified; enumeration operation might not execute.
Source=System.Data
StackTrace:
at System.Data.RBTree`1.RBTreeEnumerator.MoveNext()
at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
at System.Linq.Enumerable.<SelectIterator>d__7`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at LAPSOFT.Program.InsertCondition(String arrayHindiCap2, String arrayHindiCap5, String newArray, List`1 listHeader, String[] array) in d:\lapsoft-project\CA CUOC - Copy\Program.cs:line 418
at LAPSOFT.Program.Insert(DataTable dt, List`1 listHeader) in d:\project\CheckCopy\Program.cs:line 548
InnerException:

Related

How to break from the Catch block after throwing BadRequestException using C#

I have a method which needs to break after the BadRequestException() is thrown.
Currently after BadRequestException() is thrown, frontend shows loading bar buffering infinitely.
Please find my code below
public FeSite GetSiteBySiteId(string envCode, string siteId)
{
try
{
envCode.ThrowIfNull();
siteId.ThrowIfNull();
var watch = new Stopwatch();
watch.Start();
FeSite result = this.ExecuteAndParseWebRequestForEnv<FeSite>(envCode, $"sites/{siteId}", HttpMethod.Get);
this.LogService.Info($"FeeDataAcccess - GetSitebySiteId - {watch.ElapsedMilliseconds}ms");
return result;
}
catch (Exception e)
{
this.LogService.Error($"GetSiteBySiteId - {e.Message}");
throw new BadRequestException("Invalid siteId!");
}
}
Below method calls GetSiteBySiteId() method:
public string GetDevicesSerialNumberBySiteId(string envCode, string siteId)
{
var siteSerialNumber = "";
if (siteId != null)
{
var result = this.feeDataAccess.GetSiteBySiteId(envCode, siteId);
List<string> gatewaySiteSNlist = result.Gateways.Select(x => x.SerialNumber).ToList();
foreach (var item in gatewaySiteSNlist)
{
var siteSN = item;
siteSerialNumber += $";{siteSN};";
}
}
return siteSerialNumber;
}
I have tried this code below :
public FeSite GetSiteBySiteId(string envCode, string siteId)
{
do
{
try
{
envCode.ThrowIfNull();
siteId.ThrowIfNull();
var watch = new Stopwatch();
watch.Start();
FeSite result = this.ExecuteAndParseWebRequestForEnv<FeSite>(envCode, $"sites/{siteId}", HttpMethod.Get);
this.LogService.Info($"FeeDataAcccess - GetSitebySiteId - {watch.ElapsedMilliseconds}ms");
return result;
}
catch (Exception e)
{
this.LogService.Error($"GetSiteBySiteId - {e.Message}");
throw new BadRequestException("Invalid siteId!");
}
}
while (false);
{
break;
}
}
But I get error "No enclosing loop out of which to break or continue"
How to fix this? Thanks in advance.
public string GetDevicesSerialNumberBySiteId(string envCode, string siteId)
{
var siteSerialNumber = "";
if (siteId != null)
{
try{
var result = this.feeDataAccess.GetSiteBySiteId(envCode, siteId);
List<string> gatewaySiteSNlist = result.Gateways.Select(x => x.SerialNumber).ToList();
foreach (var item in gatewaySiteSNlist)
{
var siteSN = item;
siteSerialNumber += $";{siteSN};";
}
}catch{
//BadRequestException catch and error handling goes here
}
}
return siteSerialNumber;
}

C# SAP .net connector not returning the same data as seen in SAP GUI

I have followed the code shown on this site: "https://www.veonconsulting.com/integrating-sap-using-nco/",
I'm trying to get data from the function BAPI_PRODORD_GET_DETAIL, I tested <bapi_prodord_get_detail><number>1000262</number><struct><order_objects><header>X</header><operations>X</operations><components>X</components></order_objects></struct></bapi_prodord_get_detail>, on SAP GUI, I can see data for Header, Components & Operations, but in the code, I 'm not getting the same response, could you please help.
Code:
public bool testConnection()
{
bool state = false;
string rfcRequest = "<RFC_READ_TABLE><QUERY_TABLE>MARD</QUERY_TABLE><DELIMITER>*"
+ "</DELIMITER><ROWSKIPS>0</ROWSKIPS><ROWCOUNT>0</ROWCOUNT><TABLE><OPTIONS><ROW>"
+ "<TEXT>MATNR IN (</TEXT></ROW><ROW><TEXT>'testConnection'</TEXT></ROW><ROW>"
+ "<TEXT>)</TEXT></ROW></OPTIONS></TABLE></RFC_READ_TABLE>";
Utils.RfcClient client = new Utils.RfcClient();
try
{
XElement response = client.PullRequestToSAPrfc(rfcRequest);
state = true;
}
catch (RfcLogonException ex)
{
Console.Write("Logon Failed");
}
catch (RfcInvalidStateException ex)
{
Console.Write("RFC Failed");
}
catch (RfcBaseException ex)
{
Console.WriteLine("communication error" + ex.Message);
}
catch (Exception ex)
{
Console.Write("Connection error");
}
finally
{
//client.disconnectDestination();
}
return state;
}
public bool testConnection()
{
bool state = false;
string rfcRequest = "<bapi_prodord_get_detail><number>1000262</number><struct>"
+ "<order_objects><header>X</header><operations>X</operations><components>X"
+ "</components></order_objects></struct></bapi_prodord_get_detail>";
Utils.RfcClient client = new Utils.RfcClient();
try
{
XElement response = client.PullRequestToSAPrfc(rfcRequest);
state = true;
}
catch (RfcLogonException ex)
{
Console.Write("Logon Failed");
}
catch (RfcInvalidStateException ex)
{
Console.Write("RFC Failed");
}
catch (RfcBaseException ex)
{
Console.WriteLine("communication error" + ex.Message);
}
catch (Exception ex)
{
Console.Write("Connection error");
}
finally
{
//client.disconnectDestination();
}
return state;
}
public XElement PullRequestToSAPrfc(string XMLRequest)
{
IRfcFunction requestFn;
requestFn = PrepareRfcFunctionFromXML(XElement.Parse(XMLRequest));
RfcSessionManager.BeginContext(_ECCsystem);
requestFn.Invoke(_ECCsystem);
RfcSessionManager.EndContext(_ECCsystem);
XElement XMLResponse = PrepareXMLFromrfc(requestFn);
return XMLResponse;
}
public IRfcFunction PrepareRfcFunctionFromXML(XElement xmlFunction)
{
RfcRepository repo = _ECCsystem.Repository;
IRfcFunction RfcFunction = repo.CreateFunction(xmlFunction.Name.ToString());
foreach (XElement xelement in xmlFunction.Elements())
{
if (xelement.Name.ToString().Equals("TABLE"))
{
if (NotProcessSpecialTable(xelement))
continue;
IRfcTable options = RfcFunction.GetTable(xelement.Descendants().First().Name.ToString());
foreach (XElement row in xelement.Elements().First().Elements())
{
options.Append();
foreach (XElement rowElement in row.Elements())
{
string elementName = rowElement.Name.ToString();
RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, rowElement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
options.SetValue(elementName, elementValue);
}
}
}
else if (xelement.Name.ToString().Equals("STRUCT"))
{
IRfcStructure options = RfcFunction.GetStructure(xelement.Descendants().First().Name.ToString());
foreach (XElement structElement in xelement.Elements().First().Elements())
{
string elementName = structElement.Name.ToString();
RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, structElement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
options.SetValue(elementName, elementValue);
}
}
else
{
string elementName = xelement.Name.ToString();
RfcElementMetadata elementMeta = RfcFunction.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, xelement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
RfcFunction.SetValue(elementName, elementValue);
}
}
return RfcFunction;
}
public XElement PrepareXMLFromrfc(IRfcFunction rfcFunction)
{
var XMLRoot = new XElement(rfcFunction.Metadata.Name);
for (int functionIndex = 0; functionIndex < rfcFunction.ElementCount; functionIndex++)
{
var functionMatadata = rfcFunction.GetElementMetadata(functionIndex);
if (functionMatadata.DataType == RfcDataType.TABLE)
{
var rfcTable = rfcFunction.GetTable(functionMatadata.Name);
var XMLTable = new XElement(functionMatadata.Name);
foreach (IRfcStructure rfcStracture in rfcTable)
{
XElement XMLRow = new XElement("ROW");
for (int i = 0; i < rfcStracture.ElementCount; i++)
{
RfcElementMetadata rfcElementMetadata = rfcStracture.GetElementMetadata(i);
if (rfcElementMetadata.DataType == RfcDataType.BCD)
{ XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name))); }
else
{
XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name)));
}
}
XMLTable.Add(XMLRow);
}
XMLRoot.Add(XMLTable);
}
else if (functionMatadata.DataType == RfcDataType.STRUCTURE)
{
var rfcStructure = rfcFunction.GetStructure(functionMatadata.Name);
XElement XMLRow = new XElement(functionMatadata.Name);
for (int elementIndex = 0; elementIndex < rfcStructure.ElementCount; elementIndex++)
{
RfcElementMetadata eleMeta = rfcStructure.GetElementMetadata(elementIndex);
XMLRow.Add(new XElement(eleMeta.Name, rfcStructure.GetString(eleMeta.Name)));
}
XMLRoot.Add(XMLRow);
}
else
{
RfcElementMetadata rfcElement = rfcFunction.GetElementMetadata(functionIndex);
XMLRoot.Add(new XElement(rfcElement.Name, rfcFunction.GetString(rfcElement.Name)));
}
}
return XMLRoot;
}
# Below function is used for the data types.
private object getValueAsMetadata(ref RfcElementMetadata elementMeta, string value)
{
switch (elementMeta.DataType)
{
case RfcDataType.BCD:
return value;
case RfcDataType.NUM:
if (value.Contains("."))
{
int elementValue;
int.TryParse(value, out elementValue);
return elementValue;
}
else
{
return Convert.ToInt32(value);
}
case RfcDataType.INT1:
return Convert.ToInt32(value);
case RfcDataType.INT2:
return Convert.ToInt32(value);
case RfcDataType.INT4:
return Convert.ToInt32(value);
case RfcDataType.INT8:
return Convert.ToInt64(value);
case RfcDataType.CHAR:
return value;
case RfcDataType.DATE:
return DateTime.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
default:
return string.Empty;
}
}
You are confronted to the classic issue of external and internal values in SAP.
Your screenshot shows the ABAP Function Module Test screen in SAP system. When you enter a value in the screen, it may be transformed internally before calling the function module.
These are called the external and internal formats. "External" is what is shown in the User Interface (typed or displayed), "internal" is the value written to the database.
For instance, imagine a database object whose primary key is a GUID, this is the object key in internal format, but in the user interface this object is always referred or shown by its name (candidate key).
In your precise case, when a Production Order is a number, the internal format always contains leading zeroes on 12 digits, and the external format does not display them. In the Function Module Test screen, if you enter this external value:
1000262
it's converted to the following internal value and the BAPI is called with it:
000001000262
Generally speaking, when you call any function module from another program, you must indicate the internal value, because there's no user interface implied between the two.
i.e., use this XML in your method testConnection:
string rfcRequest = "<bapi_prodord_get_detail><number>000001000262</number><struct>"
+ "<order_objects><header>X</header><operations>X</operations><components>X"
+ "</components></order_objects></struct></bapi_prodord_get_detail>";
See also this answer about external and internal formats: Converting MATNR via conversion exit fails for custom table
If you would like to do the required field conversions programmatically, which are explained in Sandra Rossi's answer, you may use the RFMs BAPI_CONVERSION_EXT2INT, BAPI_CONVERSION_EXT2INT1, BAPI_CONVERSION_INT2EXT and BAPI_CONVERSION_INT2EXT1 for doing so.
However, every additional RFC call has of course a negative impact on the performance.
Besides, SAP Note 206068 is a good resource for an explanation of some RFC BAPI pitfalls which you also stepped in.

SSRS wont publish report but it returns successful as if it did

public static void ListFolders()
{
HomeFolderListing = new List<string>();
ReportingServiceSoapClient rs = new ReportingServiceSoapClient();
rs.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
CatalogItem[] HomeFolders = null;
string reportPath = "/";
rs.ListChildren(reportPath, true, out HomeFolders);
foreach (var homeF in HomeFolders)
{
if (homeF.Name.ToString().ToLower().Contains("base"))
{
if (homeF.Path.ToString().ToLower().Contains("/data sources/"))
{
}
else
{
Console.WriteLine("Adding reporting folder: " + homeF.Name.ToString());
HomeFolderListing.Add(homeF.Path.ToString());
}
}
}
}
public static void PublishReport()
{
foreach (string HomeFold in HomeFolderListing)
{
ReportingServiceSoapClient rs = new ReportingServiceSoapClient();
rs.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
BatchHeader bh = new BatchHeader();
string batchID = null;
rs.CreateBatch(out batchID);
bh.BatchID = batchID;
Byte[] definition = null;
Warning[] warnings = null;
try
{
FileStream stream = File.OpenRead(ReportInformation.Report2Deploy);
definition = new Byte[stream.Length];
stream.Read(definition, 0, (int)stream.Length);
stream.Close();
}
catch (Exception ex)
{
}
try
{
string filename = ReportInformation.ReportDeployNameOnly;
Console.WriteLine("Deploying Report: " + filename + " to: " + HomeFold);
rs.CreateReport(bh, filename, HomeFold, true, definition, null, out warnings);
if (warnings != null)
{
foreach (Warning warning in warnings)
{
Console.WriteLine(warning.Message);
}
}
else
Console.WriteLine("Report: {0} created successfully with no warnings", filename);
}
catch (Exception ex)
{
}
}
}
when i execute rs.CreateReport() it comes back as if it was successful with no warning, however, when i view the server it just isn't there. And yes I've looking in all the folders.
Are you sure there is no error? There's an empty catch block. The documenation says to catch a SoapException. Try this in the catch:
catch (SoapException e)
{
//Do something with the error, sample code write to console
Console.WriteLine(e.Detail.InnerXml.ToString());
}
Taken from:
http://msdn.microsoft.com/en-us/library/aa225813(v=sql.80).aspx

This IfxTransaction has completed; it is no longer usable

Q:
When I use the transactions ,I'll get the following error on about 1 out of every 100 record.
This IfxTransaction has completed; it
is no longer usable
I can't expect when the error happen or what is the reason of this error.
I try to insert about 607 record in the same transaction.
My code:
public static int InsertGroups(List<Group> groups)
{
DBConnectionForInformix con = new DBConnectionForInformix("");
con.Open_Connection();
con.Begin_Transaction();
int affectedRow = -1;
Dictionary<string, string> groupsParameter = new Dictionary<string, string>();
try
{
foreach (Group a in groups)
{
groupsParameter.Add("id", a.GroupId.ToString());
groupsParameter.Add("name", a.Name);
groupsParameter.Add("studentcount", a.StudentCount.ToString());
groupsParameter.Add("divisiontag", a.DivisionTag.ToString());
groupsParameter.Add("entireclass", a.EntireClass.ToString());
groupsParameter.Add("classid", a.ClassId.ToString());
groupsParameter.Add("depcode", a.DepCode.ToString());
groupsParameter.Add("studycode", a.StudyCode.ToString());
groupsParameter.Add("batchnum", a.BatchNum.ToString());
affectedRow = DBUtilities.InsertEntityWithTrans("groups", groupsParameter, con);
groupsParameter.Clear();
if (affectedRow < 0)
{
break;
}
}
if (affectedRow > 0)
{
con.current_trans.Commit();
}
}
catch (Exception ee)
{
string message = ee.Message;
}
con.Close_Connection();
return affectedRow;
}
public void Begin_Transaction()
{
if (this.connection.State == ConnectionState.Open)
{
this.current_trans = this.connection.BeginTransaction(IsolationLevel.Serializable);
}
}
public static int InsertEntityWithTrans(string tblName, Dictionary<string, string> dtParams, DBConnectionForInformix current_conn)
{
int Result = -1;
string[] field_names = new string[dtParams.Count];
dtParams.Keys.CopyTo(field_names, 0);
string[] field_values = new string[dtParams.Count];
string[] field_valuesParam = new string[dtParams.Count];
dtParams.Values.CopyTo(field_values, 0);
for (int i = 0; i < field_names.Length; i++)
{
field_valuesParam[i] = "?";
}
//----------------------------------------------------------------------------------------------------------------------------------------------
string insertCmd = #"INSERT INTO " + tblName + " (" + string.Join(",", field_names) + ") values (" + string.Join(",", field_valuesParam) + ")";
//----------------------------------------------------------------------------------------------------------------------------------------------
IfxCommand com = new IfxCommand(insertCmd);
for (int j = 0; j < field_names.Length; j++)
{
com.Parameters.Add("?", field_values[j]);
}
try
{
Result = current_conn.Execute_NonQueryWithTransaction(com);
if (current_conn.connectionState == ConnectionState.Open && Result > 0)//OK: logging
{
# region // Log Area
#endregion
}
}
catch (Exception ex)
{
throw;
}
return Result;
}
public int Execute_NonQueryWithTransaction(IfxCommand com)
{
string return_msg = "";
int return_val = -1;
Open_Connection();
com.Connection = this.connection;
com.Transaction = current_trans;
try
{
return_val = com.ExecuteNonQuery();
}
catch (IfxException ifxEx)// Handle IBM.data.informix : mostly catched
{
return_val = ifxEx.Errors[0].NativeError;
return_msg = return_val.ToString();
}
catch (Exception ex)// Handle all other exceptions.
{
return_msg = ex.Message;
}
finally
{
if (!string.IsNullOrEmpty(return_msg))//catch error
{
//rollback
current_trans.Rollback();
Close_Connection();
connectionstate = ConnectionState.Closed;
}
}
return return_val;
}
You seem to be handling errors and rolling back the transaction in two places (in Execute_NonQueryWithTransaction and in InsertGroups.
And the return from Execute_NonQueryWithTransaction is used both to return error codes and to return rows affected. But in InsertGroups it is checked purely as a rows affected.
Could you have an error code from Execute_NonQueryWithTransaction (so transaction rolled back) being treated as success (rows inserted) in InsertGroups and the commit then fails?
Overall the code needs significant cleanup:
A catch block to only throw is pointless and just adds noise.
Just use exceptions for error handling, all normal returns should indicate success.

Why do I get the error DTD is not allowed on this document?

Heres the code:
// iBEC/iBSS -> SHSH Generator Tool
using System;
using System.Collections.Generic;
using System.Text;
namespace SHSH_Tool
{
public enum VersionMode
{
V3_0 = 0,
V3_0_1
}
class Program
{
static void PrintUsage()
{
Console.WriteLine("iBEC/iBSS to SHSH Tool");
Console.WriteLine("Usage: SHSH_Tool -tmpfiles X:\\Path\\To\\Tmp\\Directories -output X:\\Path\\To\\00.SHSH");
Console.WriteLine("Note: If you have files for 3.0.1, use the -301 switch.");
}
static void Main(string[] args)
{
VersionMode toolMode = VersionMode.V3_0;
string firmwareRootPath = null; // #"E:\Work\Dev\iPhone\iBEC_iBSS_Grabber";
string outputFilename = null; // #"E:\Work\Dev\svn\iPhone\SHSH_Tool\3.0.shsh";
string lastArg = null;
foreach (string arg in args)
{
if (arg == "-301")
{
toolMode = VersionMode.V3_0_1;
}
if (lastArg == "-tmpfiles")
{
firmwareRootPath = arg;
}
else if (lastArg == "-output")
{
outputFilename = arg;
}
lastArg = arg.ToLower();
}
if (firmwareRootPath == null || outputFilename == null)
{
PrintUsage();
return;
}
if (!System.IO.Directory.Exists(firmwareRootPath))
{
Console.WriteLine("Unable to open TMP directories path.");
PrintUsage();
return;
}
string restoreRamDiskToIgnore = "018-5304-002.dmg";
string manifestFilename = "BuildManifest.30.xml";
string shshTemplateFilename = "3.0.shsh.template";
if (toolMode == VersionMode.V3_0_1)
{
restoreRamDiskToIgnore = "018-5804-001.dmg";
manifestFilename = "BuildManifest.30.xml";
shshTemplateFilename = "3.0.1.shsh.template";
Console.WriteLine("Operating in 3.0.1 Mode");
}
else
{
Console.WriteLine("Operating in 3.0 Mode");
}
try
{
Console.WriteLine("Reading IPSW Manifest File...");
//System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(Util.ReadEmbeddedResource(manifestFilename));
BuildManifestReader manifestReader = new BuildManifestReader(manifestFilename);
Console.WriteLine("Found Manifest Files:");
foreach (BuildManifestItem manifestItem in manifestReader.ManifestItems.Values)
{
Console.WriteLine(" - Key: " + manifestItem.Key + " [Digest: " + manifestItem.PartialDigest + "]");
}
Console.WriteLine("Processing TMP files...");
string strECID = null;
string[] subdirs = System.IO.Directory.GetDirectories(firmwareRootPath);
foreach (string subdir in subdirs)
{
if (!(subdir.Contains("Per") && subdir.EndsWith(".tmp")))
continue;
Console.WriteLine(" - Entering directory: " + subdir);
ProcessSubdirectory(subdir, manifestReader, ref strECID);
}
// Process current directory
ProcessSubdirectory(firmwareRootPath, manifestReader, ref strECID);
bool blobsOK = true;
Console.WriteLine("Verifying BLOB Data...");
foreach (BuildManifestItem manifestItem in manifestReader.ManifestItems.Values)
{
if (manifestItem.BlobData == null && manifestItem.Path != restoreRamDiskToIgnore)
{
if (manifestItem.Found)
{
Console.WriteLine(" - ERROR: Invalid signed data for " + manifestItem.Path);
}
else
{
Console.WriteLine(" - ERROR: File not found for " + manifestItem.Path);
}
blobsOK = false;
}
}
if (blobsOK)
{
Console.WriteLine("Creating custom SHSH file...");
System.IO.StreamReader shshTemplateFileHdl = new System.IO.StreamReader(Util.ReadEmbeddedResource(shshTemplateFilename));
string shshTemplateFile = shshTemplateFileHdl.ReadToEnd();
foreach (BuildManifestItem manifestItem in manifestReader.ManifestItems.Values)
{
shshTemplateFile = shshTemplateFile.Replace("[BLOB-" + manifestItem.Path + "]", manifestItem.BlobData);
shshTemplateFile = shshTemplateFile.Replace("[DIGEST-" + manifestItem.Path + "]", manifestItem.PartialDigest);
}
System.IO.StreamWriter shshFileWriter = new System.IO.StreamWriter(outputFilename);
shshFileWriter.Write(shshTemplateFile);
shshFileWriter.Close();
if (toolMode == VersionMode.V3_0)
{
Console.WriteLine("Success! 3.0 SHSH File stored at " + outputFilename);
}
else if (toolMode == VersionMode.V3_0_1)
{
Console.WriteLine("Success! 3.0.1 SHSH File stored at " + outputFilename);
}
}
else
{
Console.WriteLine("There were errors while trying to create SHSH file.");
}
}
catch (System.Exception e)
{
Console.WriteLine("There were errors while trying to create SHSH file.");
Console.WriteLine("Diagnostic: " + e.Message + " " + e.StackTrace);
}
finally
{
Console.WriteLine("Complete.");
}
}
static bool ProcessSubdirectory(string subdir, BuildManifestReader manifestReader, ref string strECID)
{
foreach (BuildManifestItem manifestItem in manifestReader.ManifestItems.Values)
{
if (manifestItem.BlobData != null)
continue;
string path = manifestItem.Path.Replace("/", "\\");
string searchPath = subdir + "\\" + path;
if (System.IO.File.Exists(searchPath))
{
Console.WriteLine(" - " + manifestItem.Path);
if (!ProcessFile(searchPath, manifestItem, ref strECID))
return false;
}
else
{
string fileOnly = manifestItem.Path.Substring(manifestItem.Path.LastIndexOf("/") + 1);
searchPath = subdir + "\\" + fileOnly;
if (System.IO.File.Exists(searchPath))
{
Console.WriteLine(" - [Alternate Path] " + fileOnly);
if (!ProcessFile(searchPath, manifestItem, ref strECID))
return false;
}
}
}
return true;
}
static bool ProcessFile(string filename, BuildManifestItem manifestItem, ref string strECID)
{
manifestItem.Found = true;
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(System.IO.File.OpenRead(filename));
binaryReader.BaseStream.Seek(-2125, System.IO.SeekOrigin.End);
byte[] magic = binaryReader.ReadBytes(4);
StringBuilder sb = new StringBuilder(100);
foreach (byte b in magic)
{
sb.Append((char)b);
}
string magicstr = sb.ToString();
if (magicstr != "DICE")
{
Console.WriteLine(" - ERROR: Magic string not found! (DICE)");
return false;
}
// chew bytes to get to the ecid
binaryReader.ReadBytes(8);
// get the ECID
byte[] ecid = binaryReader.ReadBytes(8);
StringBuilder sbECID = new StringBuilder(20);
for (int idxECID = ecid.Length - 1; idxECID >= 0; idxECID--)
{
sbECID.Append(ecid[idxECID].ToString("x2"));
}
string strThisECID = sbECID.ToString();
if (strECID != null && strThisECID != strECID)
{
Console.WriteLine(" - ERROR: ECID Mismatch (Had: " + strECID + " Found: " + strThisECID + ")");
return false;
}
else if (strECID == null)
{
strECID = strThisECID;
Console.WriteLine("Detected ECID: " + strECID);
}
binaryReader.BaseStream.Seek(-2125, System.IO.SeekOrigin.End);
byte[] signedBytes = binaryReader.ReadBytes(2125);
string signedBytesEncoded = System.Convert.ToBase64String(signedBytes);
StringBuilder formattedBlobDataBuilder = new StringBuilder(3000);
for (int idxChar = 0, colCount = 0; idxChar < signedBytesEncoded.Length; idxChar++, colCount++)
{
formattedBlobDataBuilder.Append(signedBytesEncoded[idxChar]);
if (colCount + 1 == 60)
{
formattedBlobDataBuilder.Append("\n\t\t");
colCount = -1;
}
}
string formattedBlobData = formattedBlobDataBuilder.ToString();
manifestItem.BlobData = formattedBlobData;
return true;
}
}
public class BuildManifestItem
{
string _key;
public string Key
{
get { return _key; }
set { _key = value; }
}
string _path;
public string Path
{
get { return _path; }
set { _path = value; }
}
string _partialDigest;
public string PartialDigest
{
get { return _partialDigest; }
set { _partialDigest = value; }
}
string _blobData;
public string BlobData
{
get { return _blobData; }
set { _blobData = value; }
}
bool _found;
public bool Found
{
get { return _found; }
set { _found = value; }
}
}
public class BuildManifestReader
{
private Dictionary<string, BuildManifestItem> _manifestItems;
public Dictionary<string, BuildManifestItem> ManifestItems
{
get { return _manifestItems; }
set { _manifestItems = value; }
}
public BuildManifestReader(string manifestFilename)
{
_manifestItems = new Dictionary<string, BuildManifestItem>();
System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(Util.ReadEmbeddedResource(manifestFilename));
string elementName = null;
bool foundManifest = false;
BuildManifestItem manifestItem = null;
while (xmlReader.Read())
{
if (xmlReader.NodeType == System.Xml.XmlNodeType.Element)
{
elementName = xmlReader.Name;
}
else if (elementName == "key" && xmlReader.Depth == 5 && xmlReader.NodeType == System.Xml.XmlNodeType.Text)
{
if (xmlReader.Value == "ApBoardID")
{
foundManifest = false;
}
else if (xmlReader.Value == "Manifest")
{
foundManifest = true;
}
}
else if (elementName == "key" && xmlReader.Depth == 6 && xmlReader.NodeType == System.Xml.XmlNodeType.Text)
{
if (foundManifest)
{
manifestItem = new BuildManifestItem();
manifestItem.Key = xmlReader.Value;
}
}
else if (elementName == "key" && xmlReader.NodeType == System.Xml.XmlNodeType.Text && xmlReader.Value == "Path")
{
string path = GetPath(xmlReader);
manifestItem.Path = path;
}
else if (elementName == "key" && xmlReader.NodeType == System.Xml.XmlNodeType.Text && xmlReader.Value == "PartialDigest")
{
string digest = GetPartialDigest(xmlReader);
digest = digest.Replace("\n", "");
digest = digest.Replace("\t", "");
manifestItem.PartialDigest = digest;
if (!_manifestItems.ContainsKey(manifestItem.Key + "-" + manifestItem.Path))
{
_manifestItems.Add(manifestItem.Key + "-" + manifestItem.Path, manifestItem);
}
manifestItem = null;
}
}
}
string GetPath(System.Xml.XmlReader xmlReader)
{
string elementName = null;
while (xmlReader.Read())
{
if (xmlReader.NodeType != System.Xml.XmlNodeType.Element && xmlReader.NodeType != System.Xml.XmlNodeType.Text)
continue;
if (xmlReader.NodeType == System.Xml.XmlNodeType.Element)
{
elementName = xmlReader.Name;
}
else if (elementName == "string" && xmlReader.NodeType == System.Xml.XmlNodeType.Text)
{
return xmlReader.Value;
}
else
{
return null;
}
}
return null;
}
string GetPartialDigest(System.Xml.XmlReader xmlReader)
{
string elementName = null;
while (xmlReader.Read())
{
if (xmlReader.NodeType != System.Xml.XmlNodeType.Element && xmlReader.NodeType != System.Xml.XmlNodeType.Text)
continue;
if (xmlReader.NodeType == System.Xml.XmlNodeType.Element)
{
elementName = xmlReader.Name;
}
else if (elementName == "data" && xmlReader.NodeType == System.Xml.XmlNodeType.Text)
{
return xmlReader.Value;
}
else
{
return null;
}
}
return null;
}
}
class Util
{
public static System.IO.Stream ReadEmbeddedResource(string resourceName)
{
System.Reflection.Assembly curAssembly = System.Reflection.Assembly.GetExecutingAssembly();
string [] resources = curAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(resourceName))
{
return curAssembly.GetManifestResourceStream(resource);
}
}
return null;
}
}
}
Diagnostic: For security reasons DTD is prohibited in this XML document. To enab
le DTD processing set the ProhibitDtd property on XmlReaderSettings to false and
pass the settings into XmlReader.Create method. at System.Xml.XmlTextReaderI
mpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ThrowWithoutLineInfo(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseDoctypeDecl()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at SHSH_Tool.BuildManifestReader..ctor(String manifestFilename) in C:\Users\A
dministrator\Desktop\shsh\Program.cs:line 323
at SHSH_Tool.Program.Main(String[] args) in C:\Users\Administrator\Desktop\sh
sh\Program.cs:line 87
Complete.
I don't think you gave us the actual XML document that you are reading. It probably has a "DOCTYPE" at the top which specifies a .DTD file.
Either edit the document to not have the DOCTYPE, or programatically ignore the DOCTYPE. Here is how you can do that: Ignore DOCTYPE .dtd, but .dtd file must still exist

Categories