// Parse returns filled Tag object for the given music file. func Parse(filename string) (tag Tag, err error) { cFilename := C.CString(filename) defer C.free(unsafe.Pointer(cFilename)) // Open file. cId3File, err := C.id3_file_open(cFilename, C.ID3_FILE_MODE_READONLY) if err != nil { return Tag{}, err } // TODO: Can't find out why we have segfault sometimes on this close. // But it seems that without this close file descriptors do not // leak. So, we can live without it. // defer C.id3_file_close(cId3File) // Read tag. cTag, err := C.id3_file_tag(cId3File) if err != nil { return Tag{}, err } tag = Tag{frames: make(map[string]string)} // Parse all frames. for i := C.uint(0); i < cTag.nframes; i++ { cFrame := C.id3_hlp_get_tag_frame(cTag, i) cId := C.id3_hlp_get_frame_id(cFrame) // XXX: As I understood cId memory will be GCed with id // (they share same memory). id := C.GoString(cId) cVal := C.id3_hlp_get_frame_string(cFrame) val := C.GoString(cVal) tag.frames[id] = val } return tag, nil }
// Parse returns filled Tag object for the given music file. func Parse(filename string) (tag *Tag, err os.Error) { cFilename := C.CString(filename) defer C.free(unsafe.Pointer(cFilename)) // Open file. cId3File, err := C.id3_file_open(cFilename, C.ID3_FILE_MODE_READONLY) if err != nil { return nil, err } defer C.id3_file_close(cId3File) tag = new(Tag) tag.frames = make(map[string]string) // Read tag. tag.cTag, err = C.id3_file_tag(cId3File) if err != nil { return nil, err } // Tag struct will be released with file's one. // Parse all frames. for i := _Ctype_uint(0); i < tag.cTag.nframes; i++ { cFrame := C.id3_hlp_get_tag_frame(tag.cTag, i) cId := C.id3_hlp_get_frame_id(cFrame) // XXX: As I understood cId memory will be GCed with id // (they share same memory). id := C.GoString(cId) cVal := C.id3_hlp_get_frame_string(cFrame) val := C.GoString(cVal) tag.frames[id] = val } return tag, nil }