示例#1
0
        /// <summary>
        /// Helper function that turns the list of records into a DataTable, based on a decoding function that turns the raw byte data into a String.
        /// </summary>
        /// <param name="decodeBytes">Function to decode an array of bytes to a string.</param>
        /// <param name="decodeField">Function to choose a C# .Net type for a DataColumn, based on a Starling field type.</param>
        /// <returns>DataTable populated with the database's data.</returns>
        private DataTable getDataTable(Func <byte[], String> decodeBytes, Func <StarlingDbfField.FieldType, Type> decodeField)
        {
            DataTable dt = new DataTable(table_name, "ns-" + table_name);

            // add a column for the deleted marker and populate it
            dt.Columns.Add("deleted", typeof(bool));
            foreach (StarlingDbfRecord rec in records)
            {
                dt.Rows.Add(rec.record_status == StarlingDbfRecord.status.deleted);
            }

            // add other columns
            int cell = 0;

            for (int index_field = 0; index_field < header.field_structures.Count; index_field++)
            {
                // add column
                StarlingDbfField fld     = header.field_structures[index_field];
                Type             coltype = decodeField(fld.type);
                DataColumn       dc      = new DataColumn(fld.name, coltype);
                dt.Columns.Add(dc);

                // populate column
                for (int index_rec = 0; index_rec < records.Count; index_rec++)
                {
                    // get database data as string
                    String s = decodeBytes(records[index_rec].field_contents[index_field]).Trim();

                    // add cell, with the data in the appropriate type
                    dt.Rows[index_rec].SetField(dc, decodedDataToType(s, coltype));

                    // report decoding difficulties/progress
                    if (s.Contains(StarlingDecoder.fallbackCharacter.ToString()))
                    {
                        Trace.WriteLine(String.Format("Check record {0}, field {1}.", index_rec + 1, index_field + 2));
                    }
                    reportProgress((100d * ++cell) / (records.Count * header.field_structures.Count), "Decoding");
                }
            }

            return(dt);
        }
示例#2
0
        /// <summary>
        /// Constructor method that opens and reads a Starling database (.dbf).
        /// </summary>
        /// <param name="dbfFilename">Filename of the Starling database to be read.</param>
        /// <param name="progressHandler">Optional event handler for progress reports.</param>
        public StarlingDbfReader(String dbfFilename, ReportProgressEventHandler progressHandler = null)
        {
            // register optional event
            if (progressHandler != null)
            {
                onProgressChanged += progressHandler;
            }

            // get var filename
            String VarFilename = Path.ChangeExtension(dbfFilename, "var");

            table_name = Path.GetFileNameWithoutExtension(dbfFilename);

            if (File.Exists(dbfFilename))
            {
                // read header with database structure
                reportProgress(0, "Reading header");
                header = new StarlingDbfHeader(dbfFilename);
                reportProgress(10, "Reading header: fields");

                // log header info
                Trace.WriteLine(dbfFilename);
                Trace.WriteLine(String.Format("DBF Filesize:\t\t{0}", header.getFileSize()));
                Trace.WriteLine(String.Format("Actual filesize:\t{0}", new FileInfo(dbfFilename).Length));
                Trace.WriteLine("Header");
                Trace.Indent();
                foreach (String s in header.ToString().Split('\n'))
                {
                    Trace.WriteLine(s);
                }
                Trace.Unindent();
                Trace.WriteLine(String.Format("Fields ({0})", header.field_structures.Count));
                Trace.Indent();

                // read field structures
                for (int i = 0; i < header.field_structures.Count; i++)
                {
                    StarlingDbfField rec = header.field_structures[i];

                    // log field info
                    Trace.WriteLine(String.Format("Field {0}", i));
                    Trace.Indent();
                    foreach (String s in rec.ToString().Split('\n'))
                    {
                        Trace.WriteLine(s);
                    }
                    Trace.Unindent();

                    // report progress
                    reportProgress(10 + 10 * ((float)i / header.field_structures.Count), "Reading header: fields");
                }
                Trace.Unindent();

                // read byte content for all records
                reportProgress(20, "Reading records");
                records = new List <StarlingDbfRecord>();
                using (BinaryReader dbfFile = new BinaryReader(File.OpenRead(dbfFilename), Encoding.ASCII))
                {
                    dbfFile.ReadBytes(header.HSZ);
                    while (dbfFile.BaseStream.Length - dbfFile.BaseStream.Position >= header.DRS)
                    {
                        StarlingDbfRecord rec = new StarlingDbfRecord(header, dbfFile.ReadBytes(header.DRS));
                        records.Add(rec);
                        reportProgress(20 + (40d * dbfFile.BaseStream.Position) / dbfFile.BaseStream.Length, "Reading records");
                    }
                }


                if (File.Exists(VarFilename))
                {
                    // in case of an accompanying .var file, replace byte content of record fields if they are pointers to data in .var file
                    // first check if we are dealing with a .dbf file and if it contains data pointers
                    bool varfile_is_needed = false;
                    if (String.Equals(Path.GetExtension(dbfFilename), ".dbf", StringComparison.OrdinalIgnoreCase))
                    {
                        for (int i = 0; i < header.field_structures.Count && !varfile_is_needed; i++)
                        {
                            StarlingDbfField fld = header.field_structures[i];
                            varfile_is_needed = (fld.type == StarlingDbfField.FieldType.character && fld.fieldlength == 6);
                        }
                    }

                    if (varfile_is_needed)
                    {
                        reportProgress(60, "Processing records");
                        using (BinaryReader varFile = new BinaryReader(File.OpenRead(VarFilename), Encoding.ASCII))
                        {
                            // walk through all fields (columns)
                            for (int i = 0; i < header.field_structures.Count; i++)
                            {
                                // check if the field contains data pointers, if so update each record's contents
                                StarlingDbfField fld = header.field_structures[i];
                                if (fld.type == StarlingDbfField.FieldType.character && fld.fieldlength == 6)
                                {
                                    /*
                                     * We are dealing with a pointer to the VAR file here.
                                     * The first 4 bytes give the position, the last 2 bytes give length.
                                     */
                                    foreach (StarlingDbfRecord rec in records)
                                    {
                                        byte[] old_content = rec.field_contents[i];
                                        if (!StarlingDbfRecord.emptyVarRef(old_content))
                                        {
                                            uint   position = BitConverter.ToUInt32(old_content, 0);
                                            ushort length   = BitConverter.ToUInt16(old_content, 4);
                                            varFile.BaseStream.Seek(position, SeekOrigin.Begin);
                                            byte[] new_content = varFile.ReadBytes(length);
                                            rec.field_contents[i] = new_content;
                                        }
                                    }
                                }
                                reportProgress(60 + (40d * i) / header.field_structures.Count, "Processing records");
                            }
                        }
                    }
                }

                reportProgress(100, "Database loaded");

                // log records
                //foreach (StarlingDbfRecord rec in records)
                //    Trace.WriteLine(rec.ToString());
            }
            else
            {
                Trace.WriteLine("DBF file not found.");
            }

            // unregister event
            if (progressHandler != null)
            {
                onProgressChanged -= progressHandler;
            }
        }