func (dt *DbfTable) getNormalizedFieldName(name string) (s string) { e := mahonia.NewEncoder(dt.fileEncoding) b := []byte(e.ConvertString(name)) if len(b) > 10 { b = b[0:10] } d := mahonia.NewDecoder(dt.fileEncoding) s = d.ConvertString(string(b)) return }
func (dt *DbfTable) FieldValue(row int, fieldIndex int) (value string) { // create decoder to convert bytes to utf-8 d := mahonia.NewDecoder(dt.fileEncoding) offset := int(dt.numberOfBytesInHeader) lengthOfRecord := int(dt.lengthOfEachRecord) offset = offset + (row * lengthOfRecord) recordOffset := 1 for i := 0; i < len(dt.fields); i++ { if i == fieldIndex { break } else { recordOffset += int(dt.fields[i].fieldLength) } } temp := dt.dataStore[(offset + recordOffset):((offset + recordOffset) + int(dt.fields[fieldIndex].fieldLength))] for i := 0; i < len(temp); i++ { if temp[i] == 0x00 { temp = temp[0:i] break } } s := d.ConvertString(string(temp)) //fmt.Printf("utf-8 value:[%#v]\n", s) value = strings.TrimSpace(s) //fmt.Printf("raw value:[%#v]\n", dt.dataStore[(offset + recordOffset):((offset + recordOffset) + int(dt.Fields[fieldIndex].fieldLength))]) //fmt.Printf("utf-8 value:[%#v]\n", []byte(s)) //value = string(dt.dataStore[(offset + recordOffset):((offset + recordOffset) + int(dt.Fields[fieldIndex].fieldLength))]) return }
func NewFromFile(fileName string, fileEncoding string) (table *DbfTable, err error) { // create a decoder to decode file correctly d := mahonia.NewDecoder(fileEncoding) s, err := readFile(fileName) if err != nil { return nil, err } // Create and pupulate DbaseTable struct dt := new(DbfTable) dt.fileEncoding = fileEncoding // read dbase table header information dt.fileSignature = s[0] dt.updateYear = s[1] dt.updateMonth = s[2] dt.updateDay = s[3] dt.numberOfRecords = uint32(s[4]) | (uint32(s[5]) << 8) | (uint32(s[6]) << 16) | (uint32(s[7]) << 24) dt.numberOfBytesInHeader = uint16(s[8]) | (uint16(s[9]) << 8) dt.lengthOfEachRecord = uint16(s[10]) | (uint16(s[11]) << 8) // create fieldMap to taranslate field name to index dt.fieldMap = make(map[string]int) // Number of fields in dbase table dt.numberOfFields = int((dt.numberOfBytesInHeader - 1 - 32) / 32) // populate dbf fields for i := 0; i < int(dt.numberOfFields); i++ { offset := (i * 32) + 32 fieldName := strings.Trim(d.ConvertString(string(s[offset:offset+10])), string([]byte{0})) dt.fieldMap[fieldName] = i var err error switch s[offset+11] { case 'C': err = dt.AddTextField(fieldName, s[offset+16]) case 'N': err = dt.AddNumberField(fieldName, s[offset+16]) case 'F': err = dt.AddFloatField(fieldName, s[offset+16]) case 'L': err = dt.AddBooleanField(fieldName) case 'D': err = dt.AddDateField(fieldName) } // Check return value for errors if err != nil { return nil, err } //fmt.Printf("Field name:%v\n", fieldName) //fmt.Printf("Field data type:%v\n", string(s[offset+11])) //fmt.Printf("Field length:%v\n", s[offset+16]) //fmt.Println("-----------------------------------------------") } //fmt.Printf("DbfReader:\n%#v\n", dt) //fmt.Printf("DbfReader:\n%#v\n", int(dt.Fields[2].fieldLength)) //fmt.Printf("num records in table:%v\n", (dt.numberOfRecords)) //fmt.Printf("lenght of each record:%v\n", (dt.lengthOfEachRecord)) // Since we are reading dbase file from the disk at least at this // phase changing schema of dbase file is not allowed. dt.dataEntryStarted = true // set DbfTable dataStore slice that will store the complete file in memory dt.dataStore = s return dt, nil }