diff --git a/_cgo/types.h b/_cgo/types.h index f2a91d6..5f08a7e 100644 --- a/_cgo/types.h +++ b/_cgo/types.h @@ -21,6 +21,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include + typedef struct exif_value { char *name; char *value; @@ -30,3 +32,8 @@ typedef struct exif_value { typedef struct exif_stack { struct exif_value* head; } exif_stack_t; + +typedef struct logging_option { + bool show_debug_message; + bool detail_error; +} logging_option_t; diff --git a/exif.go b/exif.go index c625bb2..a77eda5 100644 --- a/exif.go +++ b/exif.go @@ -33,7 +33,8 @@ package exif exif_value_t* pop_exif_value(exif_stack_t *); void free_exif_value(exif_value_t* n); exif_stack_t* exif_dump(ExifData *); -void set_exif_log(ExifLog *log); +void set_exif_log(ExifLog *log, logging_option_t* opt); +ExifLogCode last_exif_log_code(); */ import "C" @@ -48,6 +49,8 @@ import ( var ( ErrNoExifData = errors.New(`no EXIF data found`) ErrFoundExifInData = errors.New(`found EXIF header. OK to call Parse`) + ErrNoMemory = errors.New(`not enough memory`) + ErrCorruptData = errors.New(`data provided does not follow the specification`) ) // Data stores the EXIF tags of a file. @@ -55,6 +58,7 @@ type Data struct { exifLoader *C.ExifLoader exifLog *C.ExifLog loggingEnabled bool + option *LoggingOption Tags map[string]string } @@ -116,9 +120,16 @@ func (d *Data) Write(p []byte) (n int, err error) { runtime.SetFinalizer(d, (*Data).cleanup) } if d.loggingEnabled && d.exifLog == nil { + if d.option == nil { + d.option = &LoggingOption{} + } d.exifLog = C.exif_log_new() C.exif_loader_log(d.exifLoader, d.exifLog) - C.set_exif_log(d.exifLog) + opt := C.logging_option_t{ + show_debug_message: (C.bool)(d.option.ShowDebugMessage), + detail_error: (C.bool)(d.option.DetailError), + } + C.set_exif_log(d.exifLog, (*C.logging_option_t)(unsafe.Pointer(&opt))) C.exif_log_ref(d.exifLog) // cleanup will be defered by above } @@ -128,7 +139,17 @@ func (d *Data) Write(p []byte) (n int, err error) { if res == 1 { return len(p), nil } - return len(p), ErrFoundExifInData + + // if logging not enabled, code is always EXIF_LOG_CODE_NONE. so return ErrFoundExifInData(successful value) + code := C.last_exif_log_code() + if code == C.EXIF_LOG_CODE_NO_MEMORY { + err = ErrNoMemory + } else if code == C.EXIF_LOG_CODE_CORRUPT_DATA { + err = ErrCorruptData + } else { + err = ErrFoundExifInData + } + return len(p), err } // Parse finalizes the data loader and sets the tags @@ -158,12 +179,12 @@ func (d *Data) cleanup() { } } -type LoggingOption struct{} +type LoggingOption struct { + ShowDebugMessage bool + DetailError bool +} func (d *Data) EnableLogging(opt *LoggingOption) { d.loggingEnabled = true -} - -func (d *Data) DisableLogging() { - d.loggingEnabled = false + d.option = opt } diff --git a/exif_c.c b/exif_c.c index b729dbd..1c693d2 100644 --- a/exif_c.c +++ b/exif_c.c @@ -108,12 +108,35 @@ exif_stack_t* exif_dump(ExifData* data) { return user_data; } -void show_log(ExifLog *log, ExifLogCode code, const char *domain, const char *format, va_list args, void* _) { - printf("domain %s: %s: %s\n ", domain, exif_log_code_get_title(code), exif_log_code_get_message (code)); - vprintf(format, args); - puts(""); +typedef struct { + logging_option_t* opt; + ExifLogCode* last_code; +} logfunc_data_t; + +void show_log(ExifLog *log, ExifLogCode code, const char *domain, const char *format, va_list args, void* vdata) { + logfunc_data_t* data = vdata; + if (data->opt->show_debug_message) { + printf("domain %s: %s: %s\n ", domain, exif_log_code_get_title(code), exif_log_code_get_message (code)); + vprintf(format, args); + puts(""); + } + if (data->opt->detail_error && code != EXIF_LOG_CODE_NONE) { + *(data->last_code) = code; + } +} + +logfunc_data_t* logfunc_data() { // hold logfunc_data_t like global val + static ExifLogCode code = EXIF_LOG_CODE_NONE; + static logfunc_data_t data = {NULL, &code}; + return &data; +} + +ExifLogCode last_exif_log_code() { + return *(logfunc_data()->last_code); } -void set_exif_log(ExifLog *log) { - exif_log_set_func(log, show_log, NULL); +void set_exif_log(ExifLog *log, logging_option_t* opt) { + logfunc_data_t* d = logfunc_data(); + d->opt = opt; + exif_log_set_func(log, show_log, d); } diff --git a/exif_test.go b/exif_test.go index b004b89..d331485 100644 --- a/exif_test.go +++ b/exif_test.go @@ -2,10 +2,11 @@ package exif import ( "fmt" - "github.com/stretchr/testify/assert" "io" "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestOpen(t *testing.T) { @@ -76,3 +77,14 @@ func TestGetLatitude(t *testing.T) { assert.Equal(t, "25, 21, 32.6101", latitude) } + +func TestBrokenExif(t *testing.T) { + exif := New() + exif.EnableLogging(&LoggingOption{ShowDebugMessage: true, DetailError: true}) + file, err := os.Open("_examples/resources/broken_exif.jpg") + assert.NoError(t, err) + defer file.Close() + _, err = io.Copy(exif, file) + assert.Error(t, err) + assert.Equal(t, ErrCorruptData, err) +}