Fazlul Shahriar avatar Fazlul Shahriar committed 0fe8295

hdf4: build a tree of Records

Comments (0)

Files changed (2)

 	Tag, Ref    uint16
 	offset, len uint32
 	file        *File
+	parsing     bool
 	Info        interface{}
 }
 
 	return nil, os.NewError("tag/ref not found")
 
 found:
-	if rec.Info == nil {
+	if rec.Info == nil && !rec.parsing {
 		b, err := rec.readPayload()
 		if err != nil {
 			return nil, err
 		}
+		rec.parsing = true
+		defer func() { rec.parsing = false }()
+
 		switch rec.Tag {
 		case DFTAG_VERSION:
 			rec.Info = parseVersion(b)
 		case DFTAG_NT:
 			rec.Info = parseNumType(b)
 		case DFTAG_SDD:
-			rec.Info = parseSDD(b)
+			rec.Info, err = file.parseSDD(b)
+			if err != nil {
+				return nil, err
+			}
 		case DFTAG_NDG:
-			rec.Info = parseNDG(b)
+			rec.Info, err = file.parseNDG(b)
+			if err != nil {
+				return nil, err
+			}
 		case DFTAG_VG:
-			rec.Info = parseVGroup(b)
+			rec.Info, err = file.parseVGroup(b)
+			if err != nil {
+				return nil, err
+			}
 		default:
 			return nil, fmt.Errorf("unknown tag %d", int(rec.Tag))
 		}
 	return rec, nil
 }
 
+func (file *File) lookupNumType(tag, ref int) (*NumType, os.Error) {
+	rec, err := file.LookupRecord(int(tag), int(ref))
+	if err != nil {
+		return nil, err
+	}
+	nt, ok := rec.Info.(*NumType)
+	if !ok {
+		return nil, fmt.Errorf("parse error: expected NumType; got tag %d", int(tag))
+	}
+	return nt, nil
+}
+
 func (rec *Record) readPayload() ([]byte, os.Error) {
 	if _, err := rec.file.fd.Seek(int64(rec.offset), os.SEEK_SET); err != nil {
 		return nil, err
 
 // Scientific Data Dimension
 type SDD struct {
-	Dim                  []uint32
-	dataTag, dataRef     uint16
-	scaleTags, scaleRefs []uint16
+	Dim     []uint32
+	DataNT  *NumType
+	ScaleNT []*NumType
 }
 
-func parseSDD(b []byte) *SDD {
+func (file *File) parseSDD(b []byte) (*SDD, os.Error) {
 	sdd := new(SDD)
 	rank, b := get16(b)
 
 		sdd.Dim[i], b = get32(b)
 	}
 
-	sdd.dataTag, b = get16(b)
-	sdd.dataRef, b = get16(b)
+	tag, b := get16(b)
+	ref, b := get16(b)
+	nt, err := file.lookupNumType(int(tag), int(ref))
+	if err != nil {
+		return nil, err
+	}
+	sdd.DataNT = nt
 
-	sdd.scaleTags = make([]uint16, rank)
-	sdd.scaleRefs = make([]uint16, rank)
+	sdd.ScaleNT = make([]*NumType, rank)
 	for i := 0; i < int(rank); i++ {
-		sdd.scaleTags[i], b = get16(b)
-		sdd.scaleRefs[i], b = get16(b)
+		tag, b = get16(b)
+		ref, b = get16(b)
+		nt, err := file.lookupNumType(int(tag), int(ref))
+		if err != nil {
+			return nil, err
+		}
+		sdd.ScaleNT[i] = nt
 	}
-	return sdd
+	return sdd, nil
 }
 
 // Numeric Data Group
 type NDG struct {
-	tags, refs []uint16
+	Records []*Record
 }
 
-func parseNDG(b []byte) *NDG {
+func (file *File) parseNDG(b []byte) (*NDG, os.Error) {
 	var tag, ref uint16
 
 	ndg := new(NDG)
 	for len(b) > 0 {
 		tag, b = get16(b)
 		ref, b = get16(b)
-		ndg.tags = append(ndg.tags, tag)
-		ndg.refs = append(ndg.refs, ref)
+		rec, err := file.LookupRecord(int(tag), int(ref))
+		if err != nil {
+			continue
+		}
+		ndg.Records = append(ndg.Records, rec)
 	}
-	return ndg
+	return ndg, nil
 }
 
 type VGroup struct {
-	tags, refs   []uint16
+	Records      []*Record
 	Name         []byte
 	Class        []byte
 	extag, exref uint16
 	version      uint16
 }
 
-func parseVGroup(b []byte) *VGroup {
+func (file *File) parseVGroup(b []byte) (*VGroup, os.Error) {
 	vg := new(VGroup)
 	nelt, b := get16(b)
 
-	vg.tags = make([]uint16, nelt)
-	vg.refs = make([]uint16, nelt)
+	tags := make([]uint16, nelt)
 	for i := 0; i < int(nelt); i++ {
-		vg.tags[i], b = get16(b)
+		tags[i], b = get16(b)
 	}
 	for i := 0; i < int(nelt); i++ {
-		vg.refs[i], b = get16(b)
+		var ref uint16
+		ref, b = get16(b)
+		rec, err := file.LookupRecord(int(tags[i]), int(ref))
+		if err != nil {
+			continue
+		}
+		vg.Records = append(vg.Records, rec)
 	}
 	vg.Name, b = getstring(b)
 	vg.Class, b = getstring(b)
 	vg.extag, b = get16(b)
 	vg.exref, b = get16(b)
 	vg.version, b = get16(b)
-	return vg
+	return vg, nil
 }

hdf4/hdf4_test.go

 	}
 	defer file.Close()
 
+	for i := 0; i < len(file.Records); i++ {
+		rec := &file.Records[i]
+		switch rec.Tag {
+		case DFTAG_VERSION, DFTAG_NT, DFTAG_SDD, DFTAG_NDG, DFTAG_VG:
+			file.LookupRecord(int(rec.Tag), int(rec.Ref))
+		}
+	}
+
 	rec, err := file.LookupRecord(DFTAG_NT, -1)
 	if err != nil {
-		t.Errorf("LookupRecord failed: %v", err)
+		t.Fatalf("LookupRecord failed: %v", err)
 	}
 	log.Printf("nt = %v\n", rec.Info.(*NumType))
 
 	rec, err = file.LookupRecord(DFTAG_SDD, -1)
 	if err != nil {
-		t.Errorf("LookupRecord failed: %v", err)
+		t.Fatalf("LookupRecord failed: %v", err)
 	}
 	log.Printf("sdd = %v\n", rec.Info.(*SDD))
 
 	rec, err = file.LookupRecord(DFTAG_NDG, -1)
 	if err != nil {
-		t.Errorf("LookupRecord failed: %v", err)
+		t.Fatalf("LookupRecord failed: %v", err)
 	}
-	log.Printf("sdd = %v\n", rec.Info.(*NDG))
+	log.Printf("sdd = %T\n", rec.Info.(*NDG))
 
 	rec, err = file.LookupRecord(DFTAG_VG, -1)
 	if err != nil {
-		t.Errorf("LookupRecord failed: %v", err)
+		t.Fatalf("LookupRecord failed: %v", err)
 	}
 	vg := rec.Info.(*VGroup)
 	log.Printf("vg = %v (name=%s, class=%s)\n", vg, string(vg.Name), string(vg.Class))
 
 	log.Printf("Records=%v\n", file.Records)
 	log.Printf("Version=%v\n", file.Version)
+
+	for i := 0; i < len(file.Records); i++ {
+		rec = &file.Records[i]
+		if rec.parsing {
+			t.Errorf("Record still being parsed: %v", rec)
+		}
+		if rec.Info == nil {
+			log.Printf("tag %d not parsed\n", rec.Tag)
+		}
+	}
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.