void exif_loader_write_file (ExifLoader *l, const char *path) { FILE *f; int size; unsigned char data[1024]; if (!l) return; f = fopen (path, "rb"); if (!f) { exif_log (l->log, EXIF_LOG_CODE_NONE, "ExifLoader", _("The file '%s' could not be opened."), path); return; } while (1) { size = fread (data, 1, sizeof (data), f); if (size <= 0) break; if (!exif_loader_write (l, data, size)) break; } fclose (f); }
/** * Updates the sensor by reading the current value into it */ static void update(CAMERA_STATE *camera, struct sensor *sensor) { if (!sensor->enabled) return; struct state *state = (struct state *) sensor; if (!state->loader) state->loader = exif_loader_new(); exif_loader_reset(state->loader); exif_loader_write(state->loader, camera->imagedata.buffer, camera->imagedata.pos); ExifData *data = exif_loader_get_data(state->loader); ExifByteOrder bo = exif_data_get_byte_order(data); int valid = get_shutter_speed(data, bo, &state->shutter_speed); if (valid) valid = get_aperture(data, bo, &state->aperture); if (valid) valid = getDouble(data, bo, EXIF_TAG_ISO_SPEED_RATINGS, &state->iso); exif_data_free(data); if (valid) { // Calculate the light level state->light_level = (2.0 * log(state->aperture) - log(state->shutter_speed) - log(state->iso / 100.0)) / log(2.0); // Update the sensor sensor_log(camera, &state->sensor, (int) (state->light_level * 1000), "Lvl %.1f", state->light_level); } }
static void file_read_callback (GObject *object, GAsyncResult *res, gpointer data) { CajaImagePropertiesPage *page; GInputStream *stream; gssize count_read; GError *error; int exif_still_loading; gboolean done_reading; page = CAJA_IMAGE_PROPERTIES_PAGE (data); stream = G_INPUT_STREAM (object); error = NULL; done_reading = FALSE; count_read = g_input_stream_read_finish (stream, res, &error); if (count_read > 0) { g_assert (count_read <= sizeof(page->details->buffer)); #ifdef HAVE_EXIF exif_still_loading = exif_loader_write (page->details->exifldr, page->details->buffer, count_read); #else exif_still_loading = 0; #endif /*HAVE_EXIF*/ if (page->details->pixbuf_still_loading) { if (!gdk_pixbuf_loader_write (page->details->loader, page->details->buffer, count_read, NULL)) { page->details->pixbuf_still_loading = FALSE; } } if (page->details->pixbuf_still_loading || (exif_still_loading == 1)) { g_input_stream_read_async (G_INPUT_STREAM (stream), page->details->buffer, sizeof (page->details->buffer), 0, page->details->cancellable, file_read_callback, page); } else { done_reading = TRUE; } } else { /* either EOF, cancelled or an error occurred */ done_reading = TRUE; } if (done_reading) { load_finished (page); g_input_stream_close_async (stream, 0, page->details->cancellable, file_close_callback, page); } }
static void file_read_callback (GObject *object, GAsyncResult *res, gpointer data) { NemoImagePropertiesPage *page; GInputStream *stream; gssize count_read; GError *error; int exif_still_loading; gboolean done_reading; page = NEMO_IMAGE_PROPERTIES_PAGE (data); stream = G_INPUT_STREAM (object); error = NULL; done_reading = FALSE; count_read = g_input_stream_read_finish (stream, res, &error); if (count_read > 0) { g_assert (count_read <= sizeof(page->details->buffer)); #ifdef HAVE_EXIF exif_still_loading = exif_loader_write (page->details->exifldr, (guchar *) page->details->buffer, count_read); #else exif_still_loading = 0; #endif if (page->details->pixbuf_still_loading) { if (!gdk_pixbuf_loader_write (page->details->loader, (const guchar *) page->details->buffer, count_read, NULL)) { page->details->pixbuf_still_loading = FALSE; } } if (page->details->pixbuf_still_loading || (exif_still_loading == 1)) { g_input_stream_read_async (G_INPUT_STREAM (stream), page->details->buffer, sizeof (page->details->buffer), 0, page->details->cancellable, file_read_callback, page); } else { done_reading = TRUE; } } else { /* either EOF, cancelled or an error occurred */ done_reading = TRUE; } if (error != NULL) { char *uri = g_file_get_uri (G_FILE (object)); g_warning ("Error reading %s: %s", uri, error->message); g_free (uri); g_clear_error (&error); } if (done_reading) { load_finished (page); g_input_stream_close_async (stream, 0, page->details->cancellable, file_close_callback, page); } }
unsigned char exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len) { unsigned int i; if (!eld || (len && !buf)) return 0; switch (eld->state) { case EL_EXIF_FOUND: return exif_loader_copy (eld, buf, len); case EL_SKIP_BYTES: if (eld->size > len) { eld->size -= len; return 1; } len -= eld->size; buf += eld->size; eld->size = 0; eld->b_len = 0; switch (eld->data_format) { case EL_DATA_FORMAT_FUJI_RAW: eld->state = EL_READ_SIZE_BYTE_24; break; default: eld->state = EL_READ; break; } break; case EL_READ: default: break; } if (!len) return 1; exif_log (eld->log, EXIF_LOG_CODE_DEBUG, "ExifLoader", "Scanning %i byte(s) of data...", len); /* * First fill the small buffer. Only continue if the buffer * is filled. Note that EXIF data contains at least 12 bytes. */ i = MIN (len, sizeof (eld->b) - eld->b_len); if (i) { memcpy (&eld->b[eld->b_len], buf, i); eld->b_len += i; if (eld->b_len < sizeof (eld->b)) return 1; buf += i; len -= i; } switch (eld->data_format) { case EL_DATA_FORMAT_UNKNOWN: /* Check the small buffer against known formats. */ if (!memcmp (eld->b, "FUJIFILM", 8)) { /* Skip to byte 84. There is another offset there. */ eld->data_format = EL_DATA_FORMAT_FUJI_RAW; eld->size = 84; eld->state = EL_SKIP_BYTES; eld->size = 84; } else if (!memcmp (eld->b + 2, ExifHeader, sizeof (ExifHeader))) { /* Read the size (2 bytes). */ eld->data_format = EL_DATA_FORMAT_EXIF; eld->state = EL_READ_SIZE_BYTE_08; } default: break; } for (i = 0; i < sizeof (eld->b); i++) switch (eld->state) { case EL_EXIF_FOUND: if (!exif_loader_copy (eld, eld->b + i, sizeof (eld->b) - i)) return 0; return exif_loader_copy (eld, buf, len); case EL_SKIP_BYTES: eld->size--; if (!eld->size) eld->state = EL_READ; break; case EL_READ_SIZE_BYTE_24: eld->size |= eld->b[i] << 24; eld->state = EL_READ_SIZE_BYTE_16; break; case EL_READ_SIZE_BYTE_16: eld->size |= eld->b[i] << 16; eld->state = EL_READ_SIZE_BYTE_08; break; case EL_READ_SIZE_BYTE_08: eld->size |= eld->b[i] << 8; eld->state = EL_READ_SIZE_BYTE_00; break; case EL_READ_SIZE_BYTE_00: eld->size |= eld->b[i] << 0; switch (eld->data_format) { case EL_DATA_FORMAT_JPEG: eld->state = EL_SKIP_BYTES; eld->size -= 2; break; case EL_DATA_FORMAT_FUJI_RAW: eld->data_format = EL_DATA_FORMAT_EXIF; eld->state = EL_SKIP_BYTES; eld->size -= 86; break; case EL_DATA_FORMAT_EXIF: eld->state = EL_EXIF_FOUND; break; default: break; } break; default: switch (eld->b[i]) { case JPEG_MARKER_APP1: if (!memcmp (eld->b + i + 3, ExifHeader, MIN((ssize_t)(sizeof(ExifHeader)), MAX(0, ((ssize_t)(sizeof(eld->b))) - ((ssize_t)i) - 3)))) { eld->data_format = EL_DATA_FORMAT_EXIF; } else { eld->data_format = EL_DATA_FORMAT_JPEG; /* Probably JFIF - keep searching for APP1 EXIF*/ } eld->size = 0; eld->state = EL_READ_SIZE_BYTE_08; break; case JPEG_MARKER_DHT: case JPEG_MARKER_DQT: case JPEG_MARKER_APP0: case JPEG_MARKER_APP2: case JPEG_MARKER_APP13: case JPEG_MARKER_COM: eld->data_format = EL_DATA_FORMAT_JPEG; eld->size = 0; eld->state = EL_READ_SIZE_BYTE_08; break; case 0xff: case JPEG_MARKER_SOI: break; default: exif_log (eld->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifLoader", _("The data supplied " "does not seem to contain " "EXIF data.")); exif_loader_reset (eld); return 0; } } /* * If we reach this point, the buffer has not been big enough * to read all data we need. Fill it with new data. */ eld->b_len = 0; return exif_loader_write (eld, buf, len); }
/** * Module execution function. Receives a pointer to a file the module is to * process. The file is represented by a TskFile interface which is used * to read the contents of the file and post extracted EXIF data to the * database. * * @param pFile A pointer to a file. * @returns TskModule::OK on success, TskModule::FAIL on error. */ TskModule::Status TSK_MODULE_EXPORT run(TskFile * pFile) { if (pFile == NULL) { LOGERROR(L"ExifExtractModule: passed NULL file pointer."); return TskModule::FAIL; } try { char buffer[FILE_BUFFER_SIZE]; int bytesRead = 0; memset(buffer, 0, FILE_BUFFER_SIZE); bytesRead = pFile->read(buffer, FILE_BUFFER_SIZE); if (bytesRead < 4) return TskModule::OK; // Check the first 4 bytes to see if this is a JPEG file. // We check for both the JFIF and EXIF signatures. if (memcmp(buffer, jfifSig, sizeof(jfifSig)) != 0 && memcmp(buffer, exifSig, sizeof(exifSig)) != 0) { // It's not a JPEG file so we skip it. return TskModule::OK; } ExifLoader * exifLoader = exif_loader_new(); if (exifLoader == NULL) { LOGERROR(L"ExifExtractModule - Received NULL ExifLoader pointer"); return TskModule::FAIL; } // Feed the file content into libexif while (bytesRead > 0) { exif_loader_write(exifLoader, reinterpret_cast<unsigned char *>(buffer), bytesRead); memset(buffer, 0, FILE_BUFFER_SIZE); bytesRead = pFile->read(buffer, FILE_BUFFER_SIZE); } ExifData * exifData = exif_loader_get_data(exifLoader); // exifData will be NULL if there is no EXIF data in the image if (exifData != NULL) { // For debugging, exif_data_dump writes all exif data to stdout //exif_data_dump(exifData); extractExifData(exifData, pFile); exif_data_unref(exifData); } // Free the loader exif_loader_unref(exifLoader); } catch (TskException& tskEx) { std::wstringstream msg; msg << L"ExifExtractModule - Error processing file id " << pFile->getId() << L": " << tskEx.what(); LOGERROR(msg.str()); return TskModule::FAIL; } catch (std::exception& ex) { std::wstringstream msg; msg << L"ExifExtractModule - Error processing file id " << pFile->getId() << L": " << ex.what(); LOGERROR(msg.str()); return TskModule::FAIL; } return TskModule::OK; }