예제 #1
0
        // Example input (from DOS prompt)
        // ExtractPX0.exe "D:\Applications\APPRO6.2.27.167\OrigPickFiles\35.datafiles1.px0"
        static void Main(string[] args)
        {
            string inPath = (null == args || 1 != args.Length || null == args[0]) ? null : args[0].Trim();

            if (string.IsNullOrEmpty(inPath))
            {
                // We were expecting only a single parameter..
                ShowUsage();
                return;
            }

            var fi = new FileInfo(inPath);

            if (!fi.Exists)
            {
                // Parameter does not represent a file
                Console.WriteLine("File not found! '{0}'", inPath);
                return;
            }
            if (0 != string.Compare(fi.Extension, ".px0", true))
            {
                // Input files are expected to have a '.px0' extension!
                Console.WriteLine("Not a '.px0' file! '{0}'", inPath);
                return;
            }

            string outPath = Path.ChangeExtension(fi.FullName, ".img");

            if (File.Exists(outPath))
            {
                // Do not overwrite existing '.img' files!
                Console.WriteLine("Output file already exists! '{0}'", outPath);
                return;
            }

            var sectorDataList = new List <SectorData>();

            try
            {
                // Get PXO file bytes. If compressed data existed, these bytes will
                // represent the decompressed form!
                var px0Bytes = GetPX0ImageBytes(inPath);

                // Init a pointer we will use to traverse the PX0 file byte array
                var px0Ptr = 0;

                // Check that bytes represent valid data, read file header structure.
                var px0Hdr = PX0Header.GetHeader(px0Bytes, ref px0Ptr);
                px0Ptr++; // On first byte *after* header

                PX0CommentHeader px0CmtHdr = null;
                if ((px0Hdr.Stepping & 0x80) != 0)
                {
                    // Extract 'comment header'
                    px0CmtHdr = PX0CommentHeader.GetCommentHeader(px0Bytes, ref px0Ptr);
                    px0Ptr++; // On first byte *after* 'comment header'
                }

                // Loop over track headers
                PX0TrackHeader trkHdr;
                while ((trkHdr = PX0TrackHeader.GetTrackHeader(px0Bytes, ref px0Ptr)) != null)
                {
                    if (trkHdr.NumberOfSectors == 255)
                    {
                        break; // EOF marker!
                    }
                    px0Ptr++;  // On first byte *after* 'track header'
                    for (int sNo = 0; sNo < trkHdr.NumberOfSectors; sNo++)
                    {
                        var sectHeader = PX0SectorHeader.GetSectorHeader(px0Bytes, ref px0Ptr);

                        /*
                         * Calculate 'Logical Sector' number (from: http://stackoverflow.com/questions/5774164/lba-and-cluster or
                         * http://en.wikipedia.org/wiki/Cylinder-head-sector)
                         * There are many sector numbering schemes on disk drives. One of the earliest was CHS (Cylinder-Head-Sector).
                         * One sector can be selected by specifying the cylinder (track), read/write head and sector per track triplet.
                         * This numbering scheme depends on the actual physical characteristics of the disk drive.
                         * The first logical sector resides on cylinder 0, head 0, sector 1. The second is on sector 2, and so on.
                         * If there isn't any more sectors on the disk (eg. on a 1.44M floppy disk there's 18 sectors per track),
                         * then the next head is applied, starting on sector 1 again, and so on.
                         *
                         * You can convert CHS addresses to an absolute (or logical) sector number with a little math:
                         *
                         * LSN = (C * Nh + H) * Ns + S - 1
                         *
                         * where C, H and S are the cylinder, head and sector numbers according to CHS adressing, while Nh and Ns are
                         * the number of heads and number of sectors per track (cylinder), respectively.
                         *
                         * To convert a logical sector number into a cylinder, head and sector number:
                         * S = (LSN mod Ns) + 1
                         * H = (LSN / Ns) mod Nh
                         * C = LSN / (Ns * Nh)
                         */

                        var LSN = (trkHdr.CylNumber * px0Hdr.Sides + trkHdr.SideHeadNumber)
                                  * trkHdr.NumberOfSectors + sectHeader.SectorNumber - 1;

                        //System.Diagnostics.Debug.WriteLine(string.Format("LSN = {0} where: C: {1}, Nh: {2}, H: {3}, Ns: {4}, S: {5}",
                        //    LSN, trkHdr.CylNumber, px0Hdr.Sides, trkHdr.SideHeadNumber, trkHdr.NumberOfCylinders, sectHeader.SectorNumber));

                        sectorDataList.Add(new SectorData(LSN, sectHeader.sDta));
                        px0Ptr++; // On first byte *after* 'sector header'
                    }
                }
                if (sectorDataList.Count < 1)
                {
                    throw new Exception("No sector data extracted!");
                }

                // Sort sector data by 'logical sector number'
                sectorDataList.Sort();
            }
            catch (Exception ex)
            {
                Console.WriteLine("*ERROR* - Failed to convert file '{0}' - error: '{1}'", inPath, ex.Message);

                return;
            }

            // Write out the image file!
            try
            {
                using (var binWriter =
                           new BinaryWriter(File.Open(outPath, FileMode.Create)))
                {
                    // Write out the disk image!!
                    foreach (var td in sectorDataList)
                    {
                        binWriter.Write(td.dta);
                    }
                    binWriter.Flush();
                }
                Console.WriteLine("Finished writing image file: " + outPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine("*ERROR* - Failed to write image file '{0}' - error: '{1}'", outPath, ex.Message);
            }
        }
예제 #2
0
            public static PX0SectorHeader GetSectorHeader(byte[] dta, ref int pos)
            {
                if (pos >= dta.Length)
                {
                    throw new Exception("Sector header data missing?");
                }

                var hdr = new PX0SectorHeader(dta[pos], dta[pos + 1], dta[pos + 2],
                                              dta[pos + 3], dta[pos + 4], dta[pos + 5]);

                pos += 5; // On last byte of track header
                if ((hdr.Flags & SEC_DOS) == 0 && (hdr.Flags & SEC_NODAT) == 0)
                {
                    var  dtaBlkSize = (ushort)(dta[pos + 2] << 8 | dta[pos + 1]);
                    byte compMethod = dta[pos + 3];

                    pos += 3; // On last byte of sector data header

                    // Note that we are expanding 'dtaBlkSize-1' bytes into 'hdr.sDta.Length' bytes!
                    var dptr = 0;
                    while (dptr < hdr.sDta.Length)
                    {
                        switch (compMethod)
                        {
                        case 0:
                            // Raw sector data
                            for (var j = 0; j < hdr.sDta.Length; j++)
                            {
                                hdr.sDta[dptr++] = dta[++pos];
                            }

                            break;

                        case 1:
                            // Repeated 2-byte pattern
                            var cnt = (ushort)(dta[pos + 2] << 8 | dta[pos + 1]);
                            var b1  = dta[pos + 3];
                            var b2  = dta[pos + 4];
                            pos += 4;     // On last byte of pattern defn field
                            while (cnt > 0)
                            {
                                cnt--;
                                hdr.sDta[dptr++] = b1;
                                hdr.sDta[dptr++] = b2;
                            }
                            break;

                        case 2:
                            // RLE block
                            // Each entry begins with a 1 byte length value or 0.
                            //
                            // If 0 then this entry is for a literal block.  The next  byte
                            // indicates a length 'lgth',  and the following 'lgth' bytes are copied
                            // into  the  sector  data  as  raw  bytes  (similar  to  Encoding
                            // method==0 except for only a portion of the sector).
                            //
                            // If not 0,  then the length 'lgth'  is determined as the length value ** 2
                            // The next byte indicates a repeat count 'kount'. A block of  'lgth' bytes
                            // is then  read  once  from  the  file, and repeated in the sector data
                            // 'kount' times.
                            var lgth = dta[++pos];     // 'pos' left on length byte
                            if (0 == lgth)
                            {
                                // Literal data block
                                lgth = dta[++pos];     // 'pos' left on length byte
                                while (lgth > 0)
                                {
                                    lgth--;
                                    hdr.sDta[dptr++] = dta[++pos];
                                }
                            }
                            else
                            {
                                // Repeated fragment
                                lgth = (byte)(1 << lgth);       // Length
                                byte kount = dta[++pos];        // Count ('pos' left on count byte)
                                var  frag  = new byte[lgth];
                                for (var j = 0; j < lgth; j++)
                                {
                                    frag[j] = dta[++pos];
                                }

                                while (kount > 0)
                                {
                                    kount--;
                                    for (var j = 0; j < lgth; j++)
                                    {
                                        hdr.sDta[dptr++] = frag[j];
                                    }
                                }
                            }
                            break;

                        default:
                            throw new Exception("Invalid data mode in sector!");
                        }
                    }

                    var crc = (byte)(GetCRC(hdr.sDta, 0, hdr.sDta.Length, 0) & 0xff);
                    if (crc != hdr.CRC)
                    {
                        throw new Exception("Sector data CRC is invalid!");
                    }
                }
                return(hdr);
            }