Example #1
0
        private void read(Stream fis, ISasReaderCallback callback)
        {
            SasHeader header = readHeader(fis);

            //Logger.Info(string.Format("Header: {0}", header));
            readPages(fis, header, callback);
            //Logger.Info("Done!");
        }
Example #2
0
 public void read(ISasReaderCallback callback)
 {
     if (_stream != null)
     {
         read(_stream, callback);
     }
     else
     {
         using (FileStream fis = new FileStream(_file.PathName, FileMode.Open, FileAccess.Read))
         {
             read(fis, callback);
         }
     }
 }
Example #3
0
        private void readPages(Stream fis, SasHeader header, ISasReaderCallback callback)
        {
            List <SasSubHeader>  subHeaders    = new List <SasSubHeader>();
            List <int>           columnOffsets = new List <int>();
            List <int>           columnLengths = new List <int>();
            List <SasColumnType> columnTypes   = new List <SasColumnType>();
            bool subHeadersParsed = false;

            int rowCount = 0;

            int pageSize  = header.getPageSize();
            int pageCount = header.getPageCount();

            // these variables will define the default amount of rows per page and
            // other defaults
            int row_count    = -1;
            int row_count_fp = -1;
            int row_length   = -1;
            int col_count    = -1;

            for (int pageNumber = 0; pageNumber < pageCount; pageNumber++)
            {
                //Logger.Info(string.Format("Reading page no. {0}", pageNumber));
                byte[] pageData = new byte[pageSize];
                int    read     = fis.Read(pageData, 0, pageSize);
                if (read == -1)
                {
                    // reached end of file
                    break;
                }

                byte pageType = IO.readByte(pageData, 17);

                switch (pageType)
                {
                case 0:
                case 1:
                case 2:
                    // accepted type
                    //Logger.Info(string.Format("Page type supported: {0}", pageType));
                    break;

                case 4:
                    // accepted but not supported
                    //Logger.Info(string.Format("Page type not fully supported: {0}", pageType));
                    break;

                default:
                    throw new Exception("Page " + pageNumber + " has unknown type: " + pageType);
                }

                if (pageType == 0 || pageType == 2)
                {
                    // Read subheaders
                    int subhCount = IO.readInt(pageData, 20);
                    for (int subHeaderNumber = 0; subHeaderNumber < subhCount; subHeaderNumber++)
                    {
                        int _base = 24 + subHeaderNumber * 12;

                        int offset = IO.readInt(pageData, _base);
                        int length = IO.readInt(pageData, _base + 4);

                        if (length > 0)
                        {
                            byte[]       rawData       = IO.readBytes(pageData, offset, length);
                            byte[]       signatureData = IO.readBytes(rawData, 0, 4);
                            SasSubHeader subHeader     = new SasSubHeader(rawData,
                                                                          signatureData);
                            subHeaders.Add(subHeader);
                        }
                    }
                }

                if ((pageType == 1 || pageType == 2))
                {
                    if (!subHeadersParsed)
                    {
                        // Parse subheaders

                        SasSubHeader rowSize = getSubHeader(subHeaders,
                                                            SUBH_ROWSIZE, "ROWSIZE");
                        row_length = IO.readInt(rowSize.getRawData(), 20);
                        row_count  = IO.readInt(rowSize.getRawData(), 24);
                        int col_count_7 = IO.readInt(rowSize.getRawData(), 36);
                        row_count_fp = IO.readInt(rowSize.getRawData(), 60);

                        SasSubHeader colSize = getSubHeader(subHeaders,
                                                            SUBH_COLSIZE, "COLSIZE");
                        int col_count_6 = IO.readInt(colSize.getRawData(), 4);
                        col_count = col_count_6;

                        //if (col_count_7 != col_count_6) {
                        //    Logger.Warn(
                        //            string.Format("({0}) Column count mismatch: {1} vs. {2}",
                        //            _file.PathName, col_count_6, col_count_7 ));
                        //}

                        SasSubHeader colText = getSubHeader(subHeaders,
                                                            SUBH_COLTEXT, "COLTEXT");

                        List <SasSubHeader> colAttrHeaders = getSubHeaders(
                            subHeaders, SUBH_COLATTR, "COLATTR");
                        SasSubHeader colAttr;
                        if (!colAttrHeaders.Any())
                        {
                            throw new Exception(
                                      "No column attribute subheader found");
                        }
                        else if (colAttrHeaders.Count == 1)
                        {
                            colAttr = colAttrHeaders[0];
                        }
                        else
                        {
                            colAttr = spliceColAttrSubHeaders(colAttrHeaders);
                        }

                        SasSubHeader colName = getSubHeader(subHeaders,
                                                            SUBH_COLNAME, "COLNAME");

                        List <SasSubHeader> colLabels = getSubHeaders(subHeaders,
                                                                      SUBH_COLLABS, "COLLABS");
                        if (colLabels.Any() && colLabels.Count != col_count)
                        {
                            throw new Exception(
                                      "Unexpected column label count ("
                                      + colLabels.Count + ") expected 0 or "
                                      + col_count);
                        }

                        for (int i = 0; i < col_count; i++)
                        {
                            int _base = 12 + i * 8;

                            String columnName;
                            byte   amd = IO.readByte(colName.getRawData(), _base);
                            if (amd == 0)
                            {
                                int off = IO.readShort(colName.getRawData(),
                                                       _base + 2) + 4;
                                int len = IO.readShort(colName.getRawData(),
                                                       _base + 4);
                                columnName = IO.readString(colText.getRawData(),
                                                           off, len);
                            }
                            else
                            {
                                columnName = "COL" + i;
                            }

                            // Read column labels
                            String label;
                            if (colLabels != null && colLabels.Any())
                            {
                                _base = 42;
                                byte[] rawData = colLabels[i].getRawData();
                                int    off     = IO.readShort(rawData, _base) + 4;
                                short  len     = IO.readShort(rawData, _base + 2);
                                if (len > 0)
                                {
                                    label = IO.readString(colText.getRawData(),
                                                          off, len);
                                }
                                else
                                {
                                    label = null;
                                }
                            }
                            else
                            {
                                label = null;
                            }

                            // Read column offset, width, type (required)
                            _base = 12 + i * 12;

                            int offset = IO.readInt(colAttr.getRawData(), _base);
                            columnOffsets.Add(offset);

                            int length = IO.readInt(colAttr.getRawData(), _base + 4);
                            columnLengths.Add(length);

                            short columnTypeCode = IO.readShort(
                                colAttr.getRawData(), _base + 10);
                            SasColumnType columnType = (columnTypeCode == 1 ? SasColumnType.NUMERIC
                                    : SasColumnType.CHARACTER);
                            columnTypes.Add(columnType);

                            //Logger.Debug(string.Format(
                            //        "Column no. {0} read: name={1},label={2},type={3},length={4}",
                            //                i, columnName, label,
                            //                columnType, length ));
                            callback.column(i, columnName, label, columnType,
                                            length);
                        }

                        subHeadersParsed = true;
                    }

                    if (!callback.readData())
                    {
                        //Logger.Info("Callback decided to not read data");
                        return;
                    }

                    // Read data
                    int row_count_p;
                    int _base2;
                    if (pageType == 2)
                    {
                        row_count_p = row_count_fp;
                        int subhCount = IO.readInt(pageData, 20);
                        _base2 = 24 + subhCount * 12;
                        _base2 = _base2 + _base2 % 8;
                    }
                    else
                    {
                        row_count_p = IO.readInt(pageData, 18);
                        _base2      = 24;
                    }

                    if (row_count_p > row_count)
                    {
                        row_count_p = row_count;
                    }

                    for (int row = 0; row < row_count_p; row++)
                    {
                        Object[] rowData = new Object[col_count];
                        for (int col = 0; col < col_count; col++)
                        {
                            int off = _base2 + columnOffsets[col];
                            int len = columnLengths[col];

                            SasColumnType columnType = columnTypes[col];
                            if (len > 0)
                            {
                                byte[] raw = IO.readBytes(pageData, off, len);
                                if (columnType == SasColumnType.NUMERIC && len < 8)
                                {
                                    byte[] bb = new byte[8];
                                    for (int j = 0; j < len; j++)
                                    {
                                        bb[j] = raw[j];
                                    }
                                    for (int j = 0; j < 8 - len; j++)
                                    {
                                        bb[j] = (byte)0x00;
                                    }

                                    raw = bb;

                                    // col$length <- 8
                                    len = 8;
                                }

                                Object value;
                                if (columnType == SasColumnType.CHARACTER)
                                {
                                    String str = IO.readString(raw, 0, len);
                                    str   = str.Trim();
                                    value = str;
                                }
                                else
                                {
                                    value = IO.readNumber(raw, 0, len);
                                }
                                rowData[col] = value;
                            }
                        }

                        //Logger.Debug(string.Format("Row no. {0} read: ", row));
                        //foreach(Object c in rowData)
                        //{
                        //    Logger.Debug(c);
                        //}

                        rowCount++;
                        bool next = callback.row(rowCount, rowData);
                        if (!next)
                        {
                            //Logger.Info("Callback decided to stop iteration");
                            return;
                        }

                        _base2 = _base2 + row_length;
                    }
                }
            }
        }