Robert Robinson
New User
Joined: 28 Sep 2012 Posts: 5 Location: Canada
|
|
|
|
I must thank you all for most generously contributing to my little project - especially Enrico, Prino and thLucas.
I now have a functioning FTP downloader and unpacker integrated into my C# application. I ended up writing this from the comments in the assembler version that Enrico pointed me to in the CBT tape. It is limited in scope - it only handles variable length records up to 255 bytes and so doesn't handle any of the fixed-length control codes - but in my case I am always downloading a predictable LRECL/RECFM so it's Ok.
Please bear in mind then that this code only handles a subset of situations, but sufficient for my purposes. Thanks again for all your help, folks.
Here are the Unpack and Ebcdic conversion methods:
Code: |
private StringBuilder Unpack(MemoryStream memStream, int readCount, char recFm, int lRecl)
{
byte[] upkTxt = new byte[255]; // One unpacked line.
int i = 0;
int j = 0;
int ll = 0;
byte ch = 0;
bool eol = false;
byte[] txt = new byte[readCount]; // Create a byte array and read stream into it.
memStream.Position = 0;
memStream.Read(txt, 0, readCount);
// Build an ASCII string - guess at 4x size of packed data.
StringBuilder sb = new StringBuilder(txt.Length * 4);
while (i < txt.Length)
{
byte eb = txt[i++]; // eb = the next Ebcdic packed Byte
if (eb == 0xff) // FF = EOF
break;
/* Cloned from Rexx Unpack from ***READ FORUM RULES***.NET board */
if (eb == 0xfc || eb == 0x7c) // End of line
{
if (eb == 0xfc) // FC has ll bytes of data following
{
ll = txt[i++];
for (int k = 0; k <= ll; k++) // Length count is 1 less than should be so <=
upkTxt[j++] = txt[i++];
}
if (eb == 0x7c)
i++; // Skipping over count of trailing blanks in line
eol = true;
}
else
if (eb == 0x7a || eb == 0x7e) // Repetitions of the next character
{
// 7e = but at the end of a maximum lngth logical record
ll = txt[i++];
ch = txt[i++];
for (int k = 0; k <= ll; k++) // Repeater count is 1 less than should be so <=
upkTxt[j++] = ch;
}
else
if (eb >= 0x80) // length = (value - 80 + 1) bytes of data following.
{
ll = eb - 0x80;
for (int k = 0; k <= ll; k++) // length count is 1 less than should be so <=
upkTxt[j++] = txt[i++];
}
else
{ // Repeat blanks.
ll = eb;
ch = 0x40;
for (int k = 0; k <= ll; k++) // Repeater count is 1 less than should be so <=
upkTxt[j++] = ch;
}
// Uncomment line below to have a look a the unpacked line so far.
// string txtString = ConvertEbcdicToAscii(upkTxt, 0, j < 256 ? j : 255);
if (eol || j >= lRecl) // End of line or we've gone over the LRECL.
{ // Append to StringBuilder and start new line.
sb.Append(ConvertEbcdicToAscii(upkTxt, 0, j) + Environment.NewLine);
Array.Clear(upkTxt, 0, 255);
j = 0;
eol = false;
}
}
return sb;
}
private string ConvertEbcdicToAscii(byte[] ebcdic_bytes, int index, int length)
{
char[] chars = new char[length];
EBCDICDecoder.GetChars(ebcdic_bytes, index, length, chars, 0);
return new String(chars);
}
|
Regards, |
|
thlucas
New User
Joined: 27 Dec 2012 Posts: 6 Location: United States
|
|
|
|
Sounds good Robert - as long as it fills the need at hand, then it's all good.
I moonlight writing code for a vendor (C-Cubed), so I had to account for other situations in my C# example that I posted. If you're interested, check out their web-site. It's full of C# friendly products that allow you to do quite a few things between your MVS systems and the Windows platform. We use their products quite extensively in the automation department at First Data Corp where I work. I'm not their pimp or anything - just like their products and support. |
|