int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar) { struct direct *p,*d,**names; int nitems; struct stat stb; long nlmax; DIR *dirp = opendir (dirname);/* open directory and get status poop */ if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1; nlmax = stb.st_size / 24; /* guesstimate at number of files */ names = (struct direct **) fs_get (nlmax * sizeof (struct direct *)); nitems = 0; /* initially none found */ while (d = readdir (dirp)) { /* read directory item */ /* matches select criterion? */ if (select && !(*select) (d)) continue; /* get size of direct record for this file */ p = (struct direct *) fs_get (DIR_SIZE (d)); p->d_ino = d->d_ino; /* copy the poop */ strcpy (p->d_name,d->d_name); if (++nitems >= nlmax) { /* if out of space, try bigger guesstimate */ void *s = (void *) names; /* stupid language */ nlmax *= 2; /* double it */ fs_resize ((void **) &s,nlmax * sizeof (struct direct *)); names = (struct direct **) s; } names[nitems - 1] = p; /* store this file there */ } closedir (dirp); /* done with directory */ /* sort if necessary */ if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar); *namelist = names; /* return directory */ return nitems; /* and size */ }
static void create_dng_header(struct raw_info * raw_info){ int i,j; int extra_offset; int raw_offset; struct dir_entry ifd0[]={ {0xFE, T_LONG, 1, 1}, // NewSubFileType: Preview Image {0x100, T_LONG, 1, dng_th_width}, // ImageWidth {0x101, T_LONG, 1, dng_th_height}, // ImageLength {0x102, T_SHORT, 3, (int)cam_PreviewBitsPerSample}, // BitsPerSample: 8,8,8 {0x103, T_SHORT, 1, 1}, // Compression: Uncompressed {0x106, T_SHORT, 1, 2}, // PhotometricInterpretation: RGB {0x10E, T_ASCII, sizeof(dng_image_desc), (int)dng_image_desc}, // ImageDescription {0x10F, T_ASCII, sizeof(CAM_MAKE), (int)CAM_MAKE}, // Make {0x110, T_ASCII, 32, (int)cam_name}, // Model: Filled at header generation. {0x111, T_LONG, 1, 0}, // StripOffsets: Offset {0x112, T_SHORT, 1, 1}, // Orientation: 1 - 0th row is top, 0th column is left {0x115, T_SHORT, 1, 3}, // SamplesPerPixel: 3 {0x116, T_SHORT, 1, dng_th_height}, // RowsPerStrip {0x117, T_LONG, 1, dng_th_width*dng_th_height*3}, // StripByteCounts = preview size {0x11C, T_SHORT, 1, 1}, // PlanarConfiguration: 1 {0x131, T_ASCII|T_PTR,32, 0}, // Software {0x132, T_ASCII, 20, (int)cam_datetime}, // DateTime {0x13B, T_ASCII|T_PTR,64, (int)dng_artist_name}, // Artist: Filled at header generation. {0x14A, T_LONG, 1, 0}, // SubIFDs offset {0x8298, T_ASCII|T_PTR,64, (int)dng_copyright}, // Copyright {0x8769, T_LONG, 1, 0}, // EXIF_IFD offset {0x9216, T_BYTE, 4, 0x00000001}, // TIFF/EPStandardID: 1.0.0.0 {0xA431, T_ASCII, sizeof(cam_serial), (int)cam_serial}, // Exif.Photo.BodySerialNumber {0xA434, T_ASCII, sizeof(dng_lens_model), (int)dng_lens_model}, // Exif.Photo.LensModel {0xC612, T_BYTE, 4, 0x00000301}, // DNGVersion: 1.3.0.0 {0xC613, T_BYTE, 4, 0x00000301}, // DNGBackwardVersion: 1.1.0.0 {0xC614, T_ASCII, 32, (int)cam_name}, // UniqueCameraModel. Filled at header generation. {0xC621, T_SRATIONAL, 9, (int)&camera_sensor.color_matrix1}, {0xC627, T_RATIONAL, 3, (int)cam_AnalogBalance}, {0xC628, T_RATIONAL, 3, (int)cam_AsShotNeutral}, {0xC62A, T_SRATIONAL, 1, (int)&camera_sensor.exposure_bias}, {0xC62B, T_RATIONAL, 1, (int)cam_BaselineNoise}, {0xC62C, T_RATIONAL, 1, (int)cam_BaselineSharpness}, {0xC62E, T_RATIONAL, 1, (int)cam_LinearResponseLimit}, {0xC65A, T_SHORT, 1, 21}, // CalibrationIlluminant1 D65 {0xC65B, T_SHORT, 1, 21}, // CalibrationIlluminant2 D65 (change this if ColorMatrix2 is added) {0xC764, T_SRATIONAL, 1, (int)cam_FrameRate}, }; struct dir_entry ifd1[]={ {0xFE, T_LONG, 1, 0}, // NewSubFileType: Main Image {0x100, T_LONG|T_PTR, 1, (int)&camera_sensor.raw_rowpix}, // ImageWidth {0x101, T_LONG|T_PTR, 1, (int)&camera_sensor.raw_rows}, // ImageLength {0x102, T_SHORT|T_PTR,1, (int)&camera_sensor.bits_per_pixel},// BitsPerSample {0x103, T_SHORT, 1, 1}, // Compression: Uncompressed {0x106, T_SHORT, 1, 0x8023}, // PhotometricInterpretation: CFA {0x111, T_LONG, 1, 0}, // StripOffsets: Offset {0x115, T_SHORT, 1, 1}, // SamplesPerPixel: 1 {0x116, T_SHORT|T_PTR,1, (int)&camera_sensor.raw_rows}, // RowsPerStrip {0x117, T_LONG|T_PTR, 1, (int)&camera_sensor.raw_size}, // StripByteCounts = CHDK RAW size {0x11A, T_RATIONAL, 1, (int)cam_Resolution}, // XResolution {0x11B, T_RATIONAL, 1, (int)cam_Resolution}, // YResolution {0x11C, T_SHORT, 1, 1}, // PlanarConfiguration: 1 {0x128, T_SHORT, 1, 2}, // ResolutionUnit: inch {0x828D, T_SHORT, 2, 0x00020002}, // CFARepeatPatternDim: Rows = 2, Cols = 2 {0x828E, T_BYTE|T_PTR, 4, (int)&camera_sensor.cfa_pattern}, {0xC61A, T_LONG|T_PTR, 1, (int)&camera_sensor.black_level}, // BlackLevel {0xC61D, T_LONG|T_PTR, 1, (int)&camera_sensor.white_level}, // WhiteLevel {0xC61F, T_LONG, 2, (int)&camera_sensor.crop.origin}, {0xC620, T_LONG, 2, (int)&camera_sensor.crop.size}, {0xC68D, T_LONG, 4, (int)&camera_sensor.dng_active_area}, {0xC740, T_UNDEFINED|T_PTR, sizeof(badpixel_opcode), (int)&badpixel_opcode}, }; struct dir_entry exif_ifd[]={ {0x829A, T_RATIONAL, 1, (int)cam_shutter}, // Shutter speed {0x829D, T_RATIONAL, 1, (int)cam_aperture}, // Aperture {0x8822, T_SHORT, 1, 0}, // ExposureProgram {0x8827, T_SHORT|T_PTR,1, (int)&exif_data.iso}, // ISOSpeedRatings {0x9000, T_UNDEFINED, 4, 0x31323230}, // ExifVersion: 2.21 {0x9003, T_ASCII, 20, (int)cam_datetime}, // DateTimeOriginal {0x9201, T_SRATIONAL, 1, (int)cam_apex_shutter}, // ShutterSpeedValue (APEX units) {0x9202, T_RATIONAL, 1, (int)cam_apex_aperture}, // ApertureValue (APEX units) {0x9204, T_SRATIONAL, 1, (int)cam_exp_bias}, // ExposureBias {0x9205, T_RATIONAL, 1, (int)cam_max_av}, // MaxApertureValue {0x9207, T_SHORT, 1, 0}, // Metering mode {0x9209, T_SHORT, 1, 0}, // Flash mode {0x920A, T_RATIONAL, 1, (int)cam_focal_length}, // FocalLength {0x9290, T_ASCII|T_PTR,4, (int)cam_subsectime}, // DateTime milliseconds {0x9291, T_ASCII|T_PTR,4, (int)cam_subsectime}, // DateTimeOriginal milliseconds {0xA405, T_SHORT|T_PTR,1, (int)&exif_data.effective_focal_length}, // FocalLengthIn35mmFilm }; struct { struct dir_entry* entry; int count; // Number of entries to be saved int entry_count; // Total number of entries } ifd_list[] = { {ifd0, DIR_SIZE(ifd0), DIR_SIZE(ifd0)}, {ifd1, DIR_SIZE(ifd1), DIR_SIZE(ifd1)}, {exif_ifd, DIR_SIZE(exif_ifd), DIR_SIZE(exif_ifd)}, }; ifd0[DNG_VERSION_INDEX].offset = BE(0x01030000); ifd1[BADPIXEL_OPCODE_INDEX].type &= ~T_SKIP; // Set CFAPattern value switch (camera_sensor.cfa_pattern) { case 0x02010100: badpixel_opcode[BADPIX_CFA_INDEX] = BE(1); // BayerPhase = 1 (top left pixel is green in a green/red row) break; case 0x01020001: badpixel_opcode[BADPIX_CFA_INDEX] = BE(0); // BayerPhase = 0 (top left pixel is red) break; case 0x01000201: badpixel_opcode[BADPIX_CFA_INDEX] = BE(3); // BayerPhase = 3 (top left pixel is blue) break; case 0x00010102: badpixel_opcode[BADPIX_CFA_INDEX] = BE(2); // BayerPhase = 2 (top left pixel is green in a green/blue row) break; } // filling EXIF fields int ifd_count = DIR_SIZE(ifd_list); // Fix the counts and offsets where needed ifd0[CAMERA_NAME_INDEX].count = ifd0[UNIQUE_CAMERA_MODEL_INDEX].count = strlen(cam_name) + 1; ifd0[CHDK_VER_INDEX].offset = (int)software_ver; ifd0[CHDK_VER_INDEX].count = strlen(software_ver) + 1; ifd0[ARTIST_NAME_INDEX].count = strlen(dng_artist_name) + 1; ifd0[COPYRIGHT_INDEX].count = strlen(dng_copyright) + 1; //~ ifd0[ORIENTATION_INDEX].offset = get_orientation_for_exif(exif_data.orientation); //~ exif_ifd[EXPOSURE_PROGRAM_INDEX].offset = get_exp_program_for_exif(exif_data.exp_program); //~ exif_ifd[METERING_MODE_INDEX].offset = get_metering_mode_for_exif(exif_data.metering_mode); //~ exif_ifd[FLASH_MODE_INDEX].offset = get_flash_mode_for_exif(exif_data.flash_mode, exif_data.flash_fired); //~ exif_ifd[SSTIME_INDEX].count = exif_ifd[SSTIME_ORIG_INDEX].count = strlen(cam_subsectime)+1; // calculating offset of RAW data and count of entries for each IFD raw_offset=TIFF_HDR_SIZE; for (j=0;j<ifd_count;j++) { raw_offset+=6; // IFD header+footer for(i=0; i<ifd_list[j].entry_count; i++) { if ((ifd_list[j].entry[i].type & T_SKIP) == 0) // Exclude skipped entries (e.g. GPS info if camera doesn't have GPS) { raw_offset+=12; // IFD directory entry size int size_ext=get_type_size(ifd_list[j].entry[i].type)*ifd_list[j].entry[i].count; if (size_ext>4) raw_offset+=size_ext+(size_ext&1); } } } // creating buffer for writing data raw_offset=(raw_offset/512+1)*512; // exlusively for CHDK fast file writing dng_header_buf_size=raw_offset; dng_header_buf=umalloc(raw_offset); dng_header_buf_offset=0; if (!dng_header_buf) return; // create buffer for thumbnail thumbnail_buf = malloc(dng_th_width*dng_th_height*3); if (!thumbnail_buf) { ufree(dng_header_buf); dng_header_buf = 0; return; } // writing offsets for EXIF IFD and RAW data and calculating offset for extra data extra_offset=TIFF_HDR_SIZE; ifd0[SUBIFDS_INDEX].offset = TIFF_HDR_SIZE + ifd_list[0].count * 12 + 6; // SubIFDs offset ifd0[EXIF_IFD_INDEX].offset = TIFF_HDR_SIZE + (ifd_list[0].count + ifd_list[1].count) * 12 + 6 + 6; // EXIF IFD offset ifd0[THUMB_DATA_INDEX].offset = raw_offset; //StripOffsets for thumbnail ifd1[RAW_DATA_INDEX].offset = raw_offset + dng_th_width * dng_th_height * 3; //StripOffsets for main image for (j=0;j<ifd_count;j++) { extra_offset += 6 + ifd_list[j].count * 12; // IFD header+footer } // TIFF file header add_val_to_buf(0x4949, sizeof(short)); // little endian add_val_to_buf(42, sizeof(short)); // An arbitrary but carefully chosen number that further identifies the file as a TIFF file. add_val_to_buf(TIFF_HDR_SIZE, sizeof(int)); // offset of first IFD // writing IFDs for (j=0;j<ifd_count;j++) { int size_ext; add_val_to_buf(ifd_list[j].count, sizeof(short)); for(i=0; i<ifd_list[j].entry_count; i++) { if ((ifd_list[j].entry[i].type & T_SKIP) == 0) { add_val_to_buf(ifd_list[j].entry[i].tag, sizeof(short)); add_val_to_buf(ifd_list[j].entry[i].type & 0xFF, sizeof(short)); add_val_to_buf(ifd_list[j].entry[i].count, sizeof(int)); size_ext=get_type_size(ifd_list[j].entry[i].type)*ifd_list[j].entry[i].count; if (size_ext<=4) { if (ifd_list[j].entry[i].type & T_PTR) { add_to_buf((void*)ifd_list[j].entry[i].offset, sizeof(int)); } else { add_val_to_buf(ifd_list[j].entry[i].offset, sizeof(int)); } } else { add_val_to_buf(extra_offset, sizeof(int)); extra_offset += size_ext+(size_ext&1); } } } add_val_to_buf(0, sizeof(int)); } // writing extra data for (j=0;j<ifd_count;j++) { int size_ext; for(i=0; i<ifd_list[j].entry_count; i++) { if ((ifd_list[j].entry[i].type & T_SKIP) == 0) { size_ext=get_type_size(ifd_list[j].entry[i].type)*ifd_list[j].entry[i].count; if (size_ext>4) { add_to_buf((void*)ifd_list[j].entry[i].offset, size_ext); if (size_ext&1) add_val_to_buf(0, 1); } } } } // writing zeros to tail of dng header (just for fun) for (i=dng_header_buf_offset; i<dng_header_buf_size; i++) dng_header_buf[i]=0; }