Commits

Wez Furlong committed 613a106

Some fixes from Edriss Mirzadeh:

* Fix underflow that results in "an atom was detected that presents as larger than filesize".
* memory corruption in purge_extraneous_characters
* memory corruption in FindAtom (issue #5)

Edriss says "The code is now fully functional as far as I can tell in windows,
when compiled in MSVC++"

Comments (0)

Files changed (12)

src/AtomicParsley.h

 
 #if defined (_MSC_VER)
 #define _UNICODE
-#define strncasecmp strnicmp
+#define strncasecmp _strnicmp
 #endif
 
 #include "config.h"
 #ifndef PRIu64
 # define PRIu64 "llu"
 #endif
+#ifndef PRIu16
+# define PRIu16 "hu"
+#endif
+#ifndef PRIu8
+# define PRIu8 "hhu"
+#endif
 #ifndef SCNu32
 # define SCNu32 "lu"
 #endif
 # define SCNu16 "u"
 #endif
 
+#ifndef MIN
+//#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))
+#define MIN min
+#endif
 
 
 #ifndef MAXPATHLEN
-# define MAXPATHLEN
+# define MAXPATHLEN 255
 #endif
 
 #include "util.h"
 extern bool file_opened;
 extern bool modified_atoms;
 extern bool alter_original;
+extern bool preserve_timestamps;
 extern bool deep_atom_scan;
 extern bool cvs_build;
 extern bool force_existing_hierarchy;
                                                                    */
 //==================================================================//
 
+#include "ap_types.h"
+
 #if defined (WIN32)
 //these #defines & structs are copied from the MS W2k DDK headers so the entire DDK isn't required to be installed to compile AP_CDTOC for MCDI support
+#ifndef DEVICE_TYPE
 #define DEVICE_TYPE ULONG
+#endif
 
 #define FILE_DEVICE_CD_ROM           0x00000002
 
 #ifndef AP_TYPES_H
 #define AP_TYPES_H
 
+
+
 // Atom version 1byte/ Atom flags 3 bytes; 0x00 00 00 00
 #define AtomFlags_Data_Binary 0
 
 void APar_zlib_inflate(char* in_buffer, uint32_t in_buf_len,
 	char* out_buffer, uint32_t out_buf_len)
 {
+#if defined HAVE_ZLIB_H
 	z_stream zlib;
 
 	memset(&zlib, 0, sizeof(zlib));
 	inflateInit(&zlib);
 	inflate(&zlib, Z_PARTIAL_FLUSH);
 	inflateEnd(&zlib);
+#endif
+
 	return ;
 }
 
 	char* out_buffer, uint32_t out_buf_len)
 {
 	uint32_t compressed_bytes = 0;
+
+#if defined HAVE_ZLIB_H
 	z_stream zlib;
 
 	memset(&zlib, 0, sizeof(zlib));
 		compressed_bytes = zlib.total_out;
 		deflateEnd(&zlib);
 	}
+#endif
 	return compressed_bytes;
 }
 /*
     AtomicParsley - AP_AtomExtracts.cpp
 
-    AtomicParsley is GPL software; you can freely distribute, 
+    AtomicParsley is GPL software; you can freely distribute,
     redistribute, modify & use under the terms of the GNU General
     Public License; either version 2 or its successor.
 
     any warranty; without the implied warranty of merchantability
     or fitness for either an expressed or implied particular purpose.
 
-    Please see the included GNU General Public License (GPL) for 
+    Please see the included GNU General Public License (GPL) for
     your rights and further details; see the file COPYING. If you
     cannot, write to the Free Software Foundation, 59 Temple Place
     Suite 330, Boston, MA 02111-1307, USA.  Or www.fsf.org
 ----------------------*/
 uint8_t APar_skip_filler(FILE* isofile, uint32_t start_position) {
 	uint8_t skip_bytes = 0;
-	
+
 	while (true) {
 		uint8_t eval_byte = APar_read8(isofile, start_position + skip_bytes);
-		
+
 		if (eval_byte == 0x80 || eval_byte == 0x81 || eval_byte == 0xFE) { //seems sometimes QT writes 0x81
 			skip_bytes++;
 		} else {
 uint16_t purge_extraneous_characters(char* data) {
 	uint16_t purgings = 0;
 	uint16_t str_len = strlen(data);
-	for(uint16_t str_offset = 0; str_offset < str_len; str_len++) {
+	for(uint16_t str_offset = 0; str_offset < str_len; str_offset++) {
 		if (data[str_offset] < 32 || data[str_offset] == 127) {
 			data[str_offset] = 19;
 			purgings++;
 ----------------------*/
 char* secsTOtime(double seconds) {
 	ap_time time_duration = {0};
-	uint32_t whole_secs = seconds / 1;
-	
+	uint32_t whole_secs = (uint32_t)(seconds / 1);
+
 	time_duration.rem_millisecs = seconds - (double)whole_secs;
 	time_duration.hours = whole_secs / 3600;
 	whole_secs -= time_duration.hours * 3600;
 	time_duration.minutes = whole_secs / 60;
 	whole_secs -= time_duration.minutes * 60;
 	time_duration.seconds = whole_secs;
-	
+
 	static char hhmmss_time[20];
 	memset(hhmmss_time, 0, 20);
 	char milli[5];
 	memset(milli, 0, 5);
-	
+
 	uint8_t time_offset = 0;
 	if (time_duration.hours > 0) {
 		if (time_duration.hours < 10) {
 		memcpy(hhmmss_time+time_offset, "0.", 2);
 		time_offset+=1;
 	}
-	
+
 	sprintf(milli, "%.2lf", time_duration.rem_millisecs); //sprintf the double float into a new string because I don't know if there is a way to print without a leading zero
 	memcpy(hhmmss_time+time_offset, milli+1, 3);
-	
+
 	return *&hhmmss_time;
 }
 
 	} else {
 		mp4v_profile = track_info->m4v_profile;
 	}
-	
+
 	//unparalleled joy - Annex G table g1 - a binary listing (this from 14496-2:2001)
 	if (mp4v_profile == 0x01) {
 		fprintf(stdout, "Simple Profile, Level 1"); //00000001
 		fprintf(stdout, "Simple Profile, Level 2"); //00000010
 	} else if (mp4v_profile == 0x03) {
 		fprintf(stdout, "Simple Profile, Level 3");     //most files will land here  //00000011
-		
+
 	} else if (mp4v_profile == 0x08) {            //Compressor can create these in 3gp files
 		fprintf(stdout, "Simple Profile, Level 0"); //ISO 14496-2:2004(e) //00001000
-	
+
 	//Reserved 00000100 - 00000111
 	} else if (mp4v_profile == 0x10) {
 		fprintf(stdout, "Simple Scalable Profile, Level 0"); //00010000
 		fprintf(stdout, "Simple Scalable Profile, Level 1"); //00010001
 	} else if (mp4v_profile == 0x12) {
 		fprintf(stdout, "Simple Scalable Profile, Level 2"); //00010010
-		
-	//Reserved 00010011 - 00100000 
+
+	//Reserved 00010011 - 00100000
 	} else if (mp4v_profile == 0x21) {
 		fprintf(stdout, "Core Profile, Level 1"); //00100001
 	} else if (mp4v_profile == 0x22) {
 		fprintf(stdout, "Core Profile, Level 2"); //00100010
-	
-	//Reserved 00100011 - 00110001 
+
+	//Reserved 00100011 - 00110001
 	} else if (mp4v_profile == 0x32) {
 		fprintf(stdout, "Main Profile, Level 2"); //00110010
 	} else if (mp4v_profile == 0x33) {
 		fprintf(stdout, "Main Profile, Level 3"); //00110011
 	} else if (mp4v_profile == 0x34) {
 		fprintf(stdout, "Main Profile, Level 4"); //00110100
-		
-	//Reserved 00110101 - 01000001  
+
+	//Reserved 00110101 - 01000001
 	} else if (mp4v_profile == 0x42) {
 		fprintf(stdout, "N-bit Profile, Level 2"); //01000010
-		
-	//Reserved 01000011 - 01010000  
+
+	//Reserved 01000011 - 01010000
 	} else if (mp4v_profile == 0x51) {
 		fprintf(stdout, "Scalable Texture Profile, Level 1"); //01010001
-	
-	//Reserved 01010010 - 01100000 
+
+	//Reserved 01010010 - 01100000
 	} else if (mp4v_profile == 0x61) {
 		fprintf(stdout, "Simple Face Animation, Level 1"); //01100001
 	} else if (mp4v_profile == 0x62) {
 		fprintf(stdout, "Simple Face Animation, Level 2"); //01100010
-		
+
 	} else if (mp4v_profile == 0x63) {
 		fprintf(stdout, "Simple FBA Profile, Level 1"); //01100011
 	} else if (mp4v_profile == 0x64) {
 		fprintf(stdout, "Simple FBA Profile, Level 2"); //01100100
-		
-	//Reserved 01100101 - 01110000 
+
+	//Reserved 01100101 - 01110000
 	} else if (mp4v_profile == 0x71) {
 		fprintf(stdout, "Basic Animated Texture Profile, Level 1"); //01110001
 	} else if (mp4v_profile == 0x72) {
 		fprintf(stdout, "Basic Animated Texture Profile, Level 2"); //01110010
-		
+
 	//Reserved 01110011 - 10000000
 	} else if (mp4v_profile == 0x81) {
 		fprintf(stdout, "Hybrid Profile, Level 1"); //10000001
 	} else if (mp4v_profile == 0x82) {
 		fprintf(stdout, "Hybrid Profile, Level 2"); //10000010
-		
-	//Reserved 10000011 - 10010000 
+
+	//Reserved 10000011 - 10010000
 	} else if (mp4v_profile == 0x91) {
 		fprintf(stdout, "Advanced Real Time Simple Profile, Level 1"); //10010001
 	} else if (mp4v_profile == 0x92) {
 		fprintf(stdout, "Advanced Real Time Simple Profile, Level 3"); //10010011
 	} else if (mp4v_profile == 0x94) {
 		fprintf(stdout, "Advanced Real Time Simple Profile, Level 4"); //10010100
-	
+
 	//Reserved 10010101 - 10100000
 	} else if (mp4v_profile == 0xA1) {
 		fprintf(stdout, "Core Scalable Profile, Level 1"); //10100001
 		fprintf(stdout, "Core Scalable Profile, Level 2"); //10100010
 	} else if (mp4v_profile == 0xA3) {
 		fprintf(stdout, "Core Scalable Profile, Level 3"); //10100011
-		
-	//Reserved 10100100 - 10110000 
+
+	//Reserved 10100100 - 10110000
 	} else if (mp4v_profile == 0xB1) {
 		fprintf(stdout, "Advanced Coding Efficiency Profile, Level 1"); //10110001
 	} else if (mp4v_profile == 0xB2) {
 		fprintf(stdout, "Advanced Coding Efficiency Profile, Level 3"); //10110011
 	} else if (mp4v_profile == 0xB4) {
 		fprintf(stdout, "Advanced Coding Efficiency Profile, Level 4"); //10110100
-		
-	//Reserved 10110101 � 11000000 
+
+	//Reserved 10110101 � 11000000
 	} else if (mp4v_profile == 0xC1) {
 		fprintf(stdout, "Advanced Core Profile, Level 1"); //11000001
 	} else if (mp4v_profile == 0xC2) {
 		fprintf(stdout, "Advanced Core Profile, Level 2"); //11000010
-		
+
 	//Reserved 11000011 � 11010000
 	} else if (mp4v_profile == 0xD1) {
 		fprintf(stdout, "Advanced Scalable Texture, Level 1"); //11010001
 		fprintf(stdout, "Advanced Scalable Texture, Level 2"); //11010010
 	} else if (mp4v_profile == 0xD2) {
 		fprintf(stdout, "Advanced Scalable Texture, Level 3"); //11010011
-	
+
 	//from a draft document - 1999 (earlier than the 2000 above!!)
 	} else if (mp4v_profile == 0xE1) {
 		fprintf(stdout, "Simple Studio Profile, Level 1"); //11100001
 		fprintf(stdout, "Simple Studio Profile, Level 3"); //11100011
 	} else if (mp4v_profile == 0xE4) {
 		fprintf(stdout, "Simple Studio Profile, Level 4"); //11100100
-		
+
 	} else if (mp4v_profile == 0xE5) {
 		fprintf(stdout, "Core Studio Profile, Level 1"); //11100101
 	} else if (mp4v_profile == 0xE6) {
 		fprintf(stdout, "Core Studio Profile, Level 3"); //11100111
 	} else if (mp4v_profile == 0xE8) {
 		fprintf(stdout, "Core Studio Profile, Level 4"); //11101000
-		
+
 	//Reserved 11101001 - 11101111
 	//ISO 14496-2:2004(e)
 	} else if (mp4v_profile == 0xF0) {
 		fprintf(stdout, "Advanced Simple Profile, Level 4"); //11110100
 	} else if (mp4v_profile == 0xF5) {
 		fprintf(stdout, "Advanced Simple Profile, Level 5"); //11110101
-		
+
 	//Reserved 11110110
 	} else if (mp4v_profile == 0xF7) {
 		fprintf(stdout, "Advanced Simple Profile, Level 3b"); //11110111
-	
+
 	} else if (mp4v_profile == 0xF7) {
 		fprintf(stdout, "Fine Granularity Scalable Profile/Level 0"); //11111000
 	} else if (mp4v_profile == 0xF7) {
 		fprintf(stdout, "  MPEG-4 AAC Algorithmic Synthesis & Audio FX Profile");
 	} else if (track_info->descriptor_object_typeID == 17) {
 		fprintf(stdout, "  MPEG-4 AAC AAC Low Complexity/LC (+error recovery) Profile");
-	
+
 	} else if (track_info->descriptor_object_typeID == 19) {
 		fprintf(stdout, "  MPEG-4 AAC Long Term Prediction (+error recovery) Profile");
 	} else if (track_info->descriptor_object_typeID == 20) {
 		fprintf(stdout, "  MPEG-4 AAC Harmonic and Individual Lines plus Noise/HILN (+error recovery) Profile");
 	} else if (track_info->descriptor_object_typeID == 27) {
 		fprintf(stdout, "  MPEG-4 AAC Parametric (+error recovery) Profile");
-		
+
 	} else if (track_info->descriptor_object_typeID == 31) {
 		fprintf(stdout, "  MPEG-4 ALS Audio Lossless Coding"); //I think that mp4alsRM18 writes the channels wrong after objectedID: 0xF880 has 0 channels; 0xF890 is 2ch
 	} else {
 				APar_ShowMPEG4VisualProfileInfo(track_info);
 				break;
 			}
-			
+
 			case 0x40: { //vererable mpeg-4 aac
 				APar_ShowMPEG4AACProfileInfo(track_info);
 				break;
 			}
-			
+
 			//0x41-0x5F reserved
 			case 0x60: {
 				fprintf(stdout, "  MPEG-2 Visual Simple Profile"); //'Visual ISO/IEC 13818-2 Simple Profile'
 				fprintf(stdout, "  3GPP2 Compact Multimedia Format"); //http://www.mp4ra.org/object.html
 				break;
 			}
-			
+
 			//0xC0-0xE0 user private
 			case 0xE1: {
 				fprintf(stdout, "  3GPP2 QCELP (14K Voice)"); //http://www.mp4ra.org/object.html
 			}
 			//0xE2-0xFE user private
 			//0xFF no object type specified
-			
+
 			default: {
 				//so many profiles, so little desire to list them all (in 14496-2 which I don't have)
 				if(movie_info.contains_iods && iods_info.audio_profile == 0xFE) {
 		//http://lists.mpegif.org/pipermail/mp4-tech/2006-January/006255.html
 		//http://iphome.hhi.de/suehring/tml/doc/lenc/html/configfile_8c-source.html
 		//66=baseline, 77=main, 88=extended; 100=High, 110=High 10, 122=High 4:2:2, 144=High 4:4:4
-		
+
 		switch(track_info->profile) {
 			case 66: {
 				fprintf(stdout, "  AVC Baseline Profile");
 				break;
 			}
 		} //end profile switch
-		
+
 		//Don't have access to levels either, but working off of:
 		//http://iphome.hhi.de/suehring/tml/doc/lenc/html/configfile_8c-source.html
-		
+
 		//and the 15 levels it says here: http://www.chiariglione.org/mpeg/technologies/mp04-avc/index.htm (1b in http://en.wikipedia.org/wiki/H.264 seems nonsensical)
 		//working backwards, we get... a simple 2 digit number (with '20' just drop the 0; with 21, put in a decimal)
 		if (track_info->level > 0) {
 				default: {
 					fprintf(stdout, ", Unknown level %u.%u", track_info->level / 10, track_info->level % 10);
 				}
-			
+
 			} //end switch
 		} //end level if
 	} else if (track_type == S_AMR_TRACK) {
 			fprintf(stdout, "  AMR VBR Wide-Band. Encoder vendor code: %s\n", track_info->encoder_name);
 		}
 		free(amr_modes); amr_modes=NULL;
-		
+
 	} else if (track_type == EVRC_TRACK) {
 		fprintf(stdout, "  EVRC (Enhanced Variable Rate Coder). Encoder vendor code: %s\n", track_info->encoder_name);
-		
+
 	} else if (track_type == QCELP_TRACK) {
 		fprintf(stdout, "  QCELP (Qualcomm Code Excited Linear Prediction). Encoder vendor code: %s\n", track_info->encoder_name);
-	
+
 	} else if (track_type == S263_TRACK) {
 		if (track_info->profile == 0) {
 			fprintf(stdout, "  H.263 Baseline Profile, Level %u. Encoder vendor code: %s", track_info->level, track_info->encoder_name);
 	uint32_t sample_size = 0;
 	uint32_t sample_count = 0;
 	uint64_t total_size = 0;
-	
+
 	sample_size = APar_read32(uint32_buffer, isofile, parsedAtoms[stsz_atom].AtomicStart + 12);
 	sample_count = APar_read32(uint32_buffer, isofile, parsedAtoms[stsz_atom].AtomicStart + 16);
-	
+
 	if (sample_size == 0) {
 		for (uint64_t atom_offset = 20; atom_offset < parsedAtoms[stsz_atom].AtomicLength; atom_offset +=4) {
 			total_size += APar_read32(uint32_buffer, isofile, parsedAtoms[stsz_atom].AtomicStart + atom_offset);
 void APar_TrackLevelInfo(Trackage* track, const char* track_search_atom_name) {
 	uint8_t track_tally = 0;
 	short iter = 0;
-	
+
 	while (parsedAtoms[iter].NextAtomNumber != 0) {
-	
+
 		if ( strncmp(parsedAtoms[iter].AtomicName, "trak", 4) == 0) {
 			track_tally += 1;
 			if (track->track_num == 0) {
 				track->total_tracks += 1;
-				
+
 			} else if (track->track_num == track_tally) {
-				
+
 				short next_atom = parsedAtoms[iter].NextAtomNumber;
 				while (parsedAtoms[next_atom].AtomicLevel > parsedAtoms[iter].AtomicLevel) {
-					
+
 					if (strncmp(parsedAtoms[next_atom].AtomicName, track_search_atom_name, 4) == 0) {
-					
+
 						track->track_atom = parsedAtoms[next_atom].AtomicNumber;
 						return;
 					} else {
 		iods_offset += APar_skip_filler(isofile, iods_offset);
 		uint8_t iods_objdescrip_len = APar_read8(isofile, iods_offset);
 		iods_offset++;
-		if (iods_objdescrip_len >= 7) { 
+		if (iods_objdescrip_len >= 7) {
 			iods_info.od_profile_level = APar_read8(isofile, iods_offset+2);
 			iods_info.scene_profile_level = APar_read8(isofile, iods_offset+3);
 			iods_info.audio_profile = APar_read8(isofile, iods_offset+4);
 ----------------------*/
 void APar_Extract_esds_Info(char* uint32_buffer, FILE* isofile, short track_level_atom, TrackInfo* track_info) {
 	uint64_t offset_into_stsd = 0;
-	
+
 	while (offset_into_stsd < parsedAtoms[track_level_atom].AtomicLength) {
 		offset_into_stsd ++;
 		if ( APar_read32(uint32_buffer, isofile, parsedAtoms[track_level_atom].AtomicStart + offset_into_stsd) == 0x65736473 ) {
 			track_info->contains_esds = true;
-		
+
 			uint64_t esds_start = parsedAtoms[track_level_atom].AtomicStart + offset_into_stsd - 4;
 			uint64_t esds_length = APar_read32(uint32_buffer, isofile, esds_start);
 			uint64_t offset_into_esds = 12; //4bytes length + 4 bytes name + 4bytes null
-						
+
 			if ( APar_read8(isofile, esds_start + offset_into_esds) == 0x03 ) {
 				offset_into_esds++;
 				offset_into_esds += APar_skip_filler(isofile, esds_start + offset_into_esds);
 			} else {
 				break;
 			}
-			
+
 			//for whatever reason, when mp4box muxes in ogg into an mp4 container, section 3 gets a 0x9D byte (which doesn't fall inline with what AP considers 'filler')
 			//then again, I haven't *completely* read the ISO specifications, so I could just be missing it the the ->voluminous<- 14496-X specifications.
 			uint8_t test_byte = APar_read8(isofile, esds_start + offset_into_esds+1);
 			if (test_byte != 0) {
 				offset_into_esds++;
 			}
-			
+
 			offset_into_esds+= 4; //1 bytes section 0x03 length + 2 bytes + 1 byte
-			
+
 			if ( APar_read8(isofile, esds_start + offset_into_esds) == 0x04 ) {
 				offset_into_esds++;
 				offset_into_esds += APar_skip_filler(isofile, esds_start + offset_into_esds);
 			}
-			
+
 			uint8_t section4_length = APar_read8(isofile, esds_start + offset_into_esds);
 			if ( section4_length <= section3_length && section4_length != 0) {
 				track_info->section4_length = section4_length;
-				
+
 				if (section4_length == 0x9D) offset_into_esds++; //upper limit? when gpac puts an ogg in, section 3 is 9D - so is sec4 (section 4 real length with ogg = 0x0E86)
-				
+
 				offset_into_esds++;
 				track_info->ObjectTypeIndication = APar_read8(isofile, esds_start + offset_into_esds);
-				
+
 				//this is just so that ogg in mp4 won't have some bizarre high bitrate of like 2.8megabits/sec
 				uint8_t a_v_flag = APar_read8(isofile, esds_start + offset_into_esds + 1); //mp4box with ogg will set this to DD, mp4a has it as 0x40, mp4v has 0x20
-				
+
 				if (track_info->ObjectTypeIndication < 0xC0 && a_v_flag < 0xA0) {//0xC0 marks user streams; but things below that might still be wrong (like 0x6D - png)
 					offset_into_esds+= 5;
 					track_info->max_bitrate = APar_read32(uint32_buffer, isofile, esds_start + offset_into_esds);
 			} else {
 				break;
 			}
-			
+
 			if ( APar_read8(isofile, esds_start + offset_into_esds) == 0x05 ) {
 				offset_into_esds++;
 				offset_into_esds += APar_skip_filler(isofile, esds_start + offset_into_esds);
-			
+
 				uint8_t section5_length = APar_read8(isofile, esds_start + offset_into_esds);
 				if ( (section5_length <= section4_length || section4_length == 1) && section5_length != 0) {
 					track_info->section5_length = section5_length;
 					offset_into_esds+=1;
-					
+
 					if (track_info->type_of_track & AUDIO_TRACK) {
 						uint8_t packed_objID = APar_read8(isofile, esds_start + offset_into_esds); //its packed with channel, but channel is fetched separately
 						track_info->descriptor_object_typeID = packed_objID >> 3;
 						offset_into_esds+=1;
 
 						track_info->channels = (uint16_t)APar_ExtractChannelInfo(isofile, esds_start + offset_into_esds);
-						
+
 					} else if (track_info->type_of_track & VIDEO_TRACK) {
 						//technically, visual_object_sequence_start_code should be tested aginst 0x000001B0
 						if (APar_read16(uint32_buffer, isofile, esds_start + offset_into_esds+2) == 0x01B0) {
 				}
 				break; //uh, I've extracted the pertinent info
 			}
-		
+
 		}
 		if (offset_into_stsd > parsedAtoms[track_level_atom].AtomicLength) {
 			break;
 		track_info->modified_time = APar_read64(uint32_buffer, isofile, parsedAtoms[track->track_atom].AtomicStart + 20);
 		track_info->duration = APar_read64(uint32_buffer, isofile, parsedAtoms[track->track_atom].AtomicStart + 36);
 	}
-	
+
 	//language code
 	APar_TrackLevelInfo(track, "mdhd");
 	memset(uint32_buffer, 0, 5);
 		memset(track_info->track_hdlr_name, 0, 100);
 		APar_readX(track_info->track_hdlr_name, isofile, parsedAtoms[track->track_atom].AtomicStart + 32, parsedAtoms[track->track_atom].AtomicLength - 32);
 	}
-	
+
 	//codec section
 	APar_TrackLevelInfo(track, "stsd");
 	memset(uint32_buffer, 0, 5);
 		track_info->video_width = APar_read16(uint32_buffer, isofile, parsedAtoms[track->track_atom+1].AtomicStart + 32);
 		track_info->video_height = APar_read16(uint32_buffer, isofile, parsedAtoms[track->track_atom+1].AtomicStart + 34);
 		track_info->macroblocks = (track_info->video_width / 16) * (track_info->video_height / 16);
-		
+
 		//avc profile & level
 		if ( track_info->track_codec == 0x61766331  || track_info->track_codec == 0x64726D69) { //avc1 or drmi
 			track_info->contains_esds = false;
 				//uint8_t profile_compatibility = APar_read8(isofile, parsedAtoms[track.track_atom].AtomicStart + 10); /* is this reserved ?? */
 				track_info->level = APar_read8(isofile, parsedAtoms[track->track_atom].AtomicStart + 11);
 			}
-			
+
 			//avc1 doesn't have a hardcoded bitrate, so calculate it (off of stsz table summing) later
 		} else 	if (track_info->track_codec == 0x73323633) { //s263
 			APar_TrackLevelInfo(track, "d263");
 			if ( memcmp(parsedAtoms[track->track_atom].AtomicName, "d263", 4) == 0) {
 				APar_Extract_d263_Info(uint32_buffer, isofile, track->track_atom, track_info);
 			}
-			
+
 		} else { //mp4v
 			APar_TrackLevelInfo(track, "esds");
 			if ( memcmp(parsedAtoms[track->track_atom].AtomicName, "esds", 4) == 0) {
 				track_info->type_of_track = OTHER_TRACK; //a 'jpeg' track will fall here
 			}
 		}
-		
+
 	} else if ( track_info->type_of_track & AUDIO_TRACK) {
 		if (track_info->track_codec == 0x73616D72 || track_info->track_codec == 0x73617762
 			  || track_info->track_codec == 0x73617770 || track_info->track_codec == 0x73766D72) { //samr,sawb, svmr (sawp doesn't contain modes)
 			APar_Extract_AMR_Info(uint32_buffer, isofile, track->track_atom+2, track_info);
-		
+
 		} else if (track_info->track_codec == 0x73657663) { //sevc
 			APar_TrackLevelInfo(track, "devc");
 			if ( memcmp(parsedAtoms[track->track_atom].AtomicName, "devc", 4) == 0) {
 				APar_Extract_devc_Info(isofile, track->track_atom, track_info);
 			}
-			
-		} else if (track_info->track_codec == 0x73716370) { //sqcp 
+
+		} else if (track_info->track_codec == 0x73716370) { //sqcp
 			APar_TrackLevelInfo(track, "dqcp");
 			if ( memcmp(parsedAtoms[track->track_atom].AtomicName, "dqcp", 4) == 0) {
 				APar_Extract_devc_Info(isofile, track->track_atom, track_info); //its the same thing
 			}
-			
-		} else if (track_info->track_codec == 0x73736D76) { //ssmv 
+
+		} else if (track_info->track_codec == 0x73736D76) { //ssmv
 			APar_TrackLevelInfo(track, "dsmv");
 			if ( memcmp(parsedAtoms[track->track_atom].AtomicName, "dsmv", 4) == 0) {
 				APar_Extract_devc_Info(isofile, track->track_atom, track_info); //its the same thing
 			}
-		
+
 		} else {
 			APar_Extract_esds_Info(uint32_buffer, isofile, track->track_atom, track_info);
 		}
 	}
-	
+
 	//in case bitrate isn't found, manually determine it off of stsz summing
 	if ( (track_info->type_of_track & AUDIO_TRACK || track_info->type_of_track & VIDEO_TRACK ) && track_info->avg_bitrate == 0)  {
 		if (track_info->track_codec == 0x616C6163 ) { //alac
 			track_info->channels = APar_read16(uint32_buffer, isofile, parsedAtoms[track->track_atom+1].AtomicStart + 24);
 		}
 	}
-	
+
 	APar_TrackLevelInfo(track, "stsz");
 	if (memcmp(parsedAtoms[track->track_atom].AtomicName, "stsz", 4) == 0) {
 		track_info->sample_aggregate = calcuate_sample_size(uint32_buffer, isofile, track->track_atom);
 		memset(uint32_buffer, 0, 5);
 		track_info->protected_codec = APar_read32(uint32_buffer, isofile, parsedAtoms[track->track_atom].AtomicStart + 8);
 	}
-		
+
 	//Encoder string; occasionally, it appears under stsd for a video track; it is typcally preceded by ' �' (1st char is unprintable) or 0x01B2
 	if (track_info->contains_esds) {
 		APar_TrackLevelInfo(track, "esds");
-		
+
 		//technically, user_data_start_code should be tested aginst 0x000001B2; TODO: it should only be read up to section 3's length too
 		_offset = APar_FindValueInAtom(uint32_buffer, isofile, track->track_atom, 24, 0x01B2);
-		
+
 		if (_offset > 0 && _offset < parsedAtoms[track->track_atom].AtomicLength) {
 			_offset +=2;
 			memset(track_info->encoder_name, 0, parsedAtoms[track->track_atom].AtomicLength - _offset);
     Get information out of 'mvhd' - most important of which are timescale & duration which get used to calcuate bitrate if needed and determine duration
 		of a track in seconds. A rough approximation of the overall bitrate is done off this too using the sum of the mdat lengths.
 ----------------------*/
-void APar_ExtractMovieDetails(char* uint32_buffer, FILE* isofile, AtomicInfo* mvhd_atom) {	
+void APar_ExtractMovieDetails(char* uint32_buffer, FILE* isofile, AtomicInfo* mvhd_atom) {
 	if (mvhd_atom->AtomicVerFlags & 0x01000000) {
 		movie_info.creation_time = APar_read64(uint32_buffer, isofile, mvhd_atom->AtomicStart + 12);
 		movie_info.modified_time = APar_read64(uint32_buffer, isofile, mvhd_atom->AtomicStart + 20);
 		movie_info.playback_rate = APar_read32(uint32_buffer, isofile, mvhd_atom->AtomicStart + 28);
 		movie_info.volume = APar_read16(uint32_buffer, isofile, mvhd_atom->AtomicStart + 32);
 	}
-	
+
 	movie_info.seconds = (float)movie_info.duration / (float)movie_info.timescale;
 #if defined (_MSC_VER)
 	__int64 media_bits = (__int64)mdatData * 8;
 		fprintf(stdout, "  %.3f sec", (float)track_info->duration / (float)movie_info.timescale);
 #endif
 	}
-						
+
 	if (track_info->track_codec == 0x6D703476 ) { //mp4v profile
-		APar_ShowObjectProfileInfo(MP4V_TRACK, track_info);											
+		APar_ShowObjectProfileInfo(MP4V_TRACK, track_info);
 	} else if (track_info->track_codec == 0x6D703461 || track_info->protected_codec == 0x6D703461 ) { //mp4a profile
 		APar_ShowObjectProfileInfo(AUDIO_TRACK, track_info);
 	} else if (track_info->track_codec == 0x616C6163) { //alac - can't figure out a hardcoded bitrate either
 		APar_ShowObjectProfileInfo(track_info->type_of_track, track_info);
 		fprintf(stdout, "\n");
 	}
-					
-	if (track_info->type_of_track & VIDEO_TRACK && 
+
+	if (track_info->type_of_track & VIDEO_TRACK &&
 			( ( track_info->max_bitrate > 0 && track_info->ObjectTypeIndication == 0x20) || track_info->avc_version == 1 || track_info->protected_codec != 0) ) {
 		fprintf(stdout, "  %ux%u  (%u macroblocks)\n", track_info->video_width, track_info->video_height, track_info->macroblocks);
 	} else if (track_info->type_of_track & VIDEO_TRACK) {
 void APar_ExtractDetails(FILE* isofile, uint8_t optional_output) {
 	char* uint32_buffer=(char*)malloc( sizeof(char)*5 );
 	Trackage track = {0};
-	
+
 	AtomicInfo* mvhdAtom = APar_FindAtom("moov.mvhd", false, VERSIONED_ATOM, 0);
 	if (mvhdAtom != NULL) {
 		APar_ExtractMovieDetails(uint32_buffer, isofile, mvhdAtom);
 			fprintf(stdout, "  Presentation Modification Date (UTC): %s\n", APar_extract_UTC(movie_info.modified_time) );
 		}
 	}
-		
+
 	AtomicInfo* iodsAtom = APar_FindAtom("moov.iods", false, VERSIONED_ATOM, 0);
 	if (iodsAtom != NULL) {
 		movie_info.contains_iods = true;
 		APar_Extract_iods_Info(isofile, iodsAtom);
 	}
-	
+
 	if (optional_output & SHOW_TRACK_INFO) {
 		APar_TrackLevelInfo(&track, NULL); //With track_num set to 0, it will return the total trak atom into total_tracks here.
 
 		fprintf(stdout, "Low-level details. Total tracks: %u \n", track.total_tracks);
 		fprintf(stdout, "Trk  Type  Handler                    Kind  Lang  Bytes\n");
-		
+
 		if (track.total_tracks > 0) {
 			while (track.total_tracks > track.track_num) {
 				track.track_num+= 1;
 				TrackInfo track_info = {0};
-				
+
 				//tracknum, handler type, handler name
 				APar_ExtractTrackDetails(uint32_buffer, isofile, &track, &track_info);
 				uint16_t more_whitespace = purge_extraneous_characters(track_info.track_hdlr_name);
-				
+
 				if (strlen(track_info.track_hdlr_name) == 0) {
 					memcpy(track_info.track_hdlr_name, "[none listed]", 13);
 				}
 				fprintf(stdout, "%u    %s  %s", track.track_num,  uint32tochar4(track_info.track_type, uint32_buffer), track_info.track_hdlr_name);
-				
+
 				uint16_t handler_len = strlen(track_info.track_hdlr_name);
 				if (handler_len < 25 + more_whitespace) {
 					for (uint16_t i=handler_len; i < 25 + more_whitespace; i++) {
 						fprintf(stdout, " ");
 					}
 				}
-				
+
 				//codec, language
 				fprintf(stdout, "  %s  %s   %" PRIu64 "", uint32tochar4(track_info.track_codec, uint32_buffer), track_info.unpacked_lang, track_info.sample_aggregate);
-				
+
 				if (track_info.encoder_name[0] != 0 && track_info.contains_esds) {
 					purge_extraneous_characters(track_info.encoder_name);
 					fprintf(stdout, "   Encoder: %s", track_info.encoder_name);
 				if (track_info.type_of_track & DRM_PROTECTED_TRACK) {
 					fprintf(stdout, " (protected %s)", uint32tochar4(track_info.protected_codec, uint32_buffer) );
 				}
-				
-				fprintf(stdout, "\n");			
+
+				fprintf(stdout, "\n");
 				/*---------------------------------*/
-				
+
 				if (track_info.type_of_track & VIDEO_TRACK || track_info.type_of_track & AUDIO_TRACK) {
 					APar_Print_TrackDetails(&track_info);
 				}
-				
+
 				if (optional_output & SHOW_DATE_INFO) {
 					fprintf(stdout, "       Creation Date (UTC):     %s\n", APar_extract_UTC(track_info.creation_time) );
 					fprintf(stdout, "       Modification Date (UTC): %s\n", APar_extract_UTC(track_info.modified_time) );
 				}
-					
+
 			}
 		}
 	}
 	uint8_t file_type_offset = 0;
 	uint32_t compatible_brand = 0;
 	bool cb_V2ISOBMFF = false;
-	
+
 	APar_read32(buffer, a_file, 4);
 	if (memcmp(buffer, "ftyp", 4) == 0) {
 		atom_length = APar_read32(buffer, a_file, 0);
 			}
 		}
 	}
-	
+
 	if (atom_length > 0) {
 		memset(buffer, 0, 16);
 		APar_readX(buffer, a_file, 8+file_type_offset, 4);
 		printBOM();
 		fprintf(stdout, " Major Brand: %s", buffer);
 		APar_IdentifyBrand(buffer);
-		
+
 		if (memcmp(buffer, "isom", 4) == 0) {
 			APar_ScanAtoms(filepath); //scan_file = true;
 		}
-		
+
 		uint32_t minor_version = APar_read32(buffer, a_file, 12+file_type_offset);
 		fprintf(stdout, "  -  version %u\n", minor_version);
-		
+
 		fprintf(stdout, " Compatible Brands:");
 		for (uint64_t i = 16+file_type_offset; i < atom_length; i+=4) {
 			APar_readX(buffer, a_file, i, 4);
 		}
 		fprintf(stdout, "\n");
 	}
-	
+
 	APar_OpenISOBaseMediaFile(filepath, false);
-	
+
 	fprintf(stdout, " Tagging schemes available:\n");
 	switch(metadata_style) {
 		case ITUNES_STYLE: {
 		fprintf(stdout, "   ID3 tags on ID32 atoms @ file/movie/track level allowed.\n");
 	}
 	fprintf(stdout, "   ISO-copyright notices @ movie and/or track level allowed.\n   uuid private user extension tags allowed.\n");
-	
+
 	free(buffer); buffer=NULL;
 	return;
 }
 	if (test_file != NULL) {
 		
 		fwrite(buffer, (size_t)buff_len, 1, test_file);
+		fclose(test_file);
 	}
-	fclose(test_file);
 	free(indy_atom_path);
 	return;
 }
 					//skip the required separator for multiple strings
 					if (textencoding == TE_LATIN1 || textencoding == TE_UTF8) {
 						offset_into_frame += 1;
-					} else if (textencoding == TE_UTF16LE_WITH_BOM || textencoding == TE_UTF16LE_WITH_BOM) {
+					} else if (textencoding == TE_UTF16LE_WITH_BOM) {
 						offset_into_frame += 2;
 					}
 					
 					//multiple id3v2.4 strings should be separated with a single NULL byte; some implementations might terminate the string AND use a NULL separator
 					if (textencoding == TE_LATIN1 || textencoding == TE_UTF8) {
 						if ((frame_ptr + offset_into_frame)[0] == 0) offset_into_frame+=1;
-					} else if (textencoding == TE_UTF16LE_WITH_BOM || textencoding == TE_UTF16LE_WITH_BOM) {
+					} else if (textencoding == TE_UTF16LE_WITH_BOM) {
 						if ((frame_ptr + offset_into_frame)[0] == 0 && (frame_ptr + offset_into_frame)[1] == 0) offset_into_frame+=2;
 					}
 					
 					//a 3rd NULL would not be good
 					if (textencoding == TE_LATIN1 || textencoding == TE_UTF8) {
 						if ((frame_ptr + offset_into_frame)[0] == 0) break;
-					} else if (textencoding == TE_UTF16LE_WITH_BOM || textencoding == TE_UTF16LE_WITH_BOM) {
+					} else if (textencoding == TE_UTF16LE_WITH_BOM) {
 						if ((frame_ptr + offset_into_frame)[0] == 0 && (frame_ptr + offset_into_frame)[1] == 0) break;
 					}
 					
 			if (genre_idx != 0xFF) {
 				char genre_str_idx[2];
 				genre_str_idx[0] = 0; genre_str_idx[1] = 0; genre_str_idx[1] = 0;
-				sprintf(genre_str_idx, "%hhu", genre_idx);
+				sprintf(genre_str_idx, "%" PRIu8 "", genre_idx);
 				APar_FrameDataPut(targetFrame, genre_str_idx, adjunct_payloads, str_encoding);
 			} else {
 				APar_FrameDataPut(targetFrame, frame_payload, adjunct_payloads, str_encoding);
 			ID3v2Fields* afield = aframe->ID3v2_Frame_Fields+id3fld;
 			ID3v2Fields* freefield = NULL;
 			while (true) {
-				if ( afield->field_string != NULL ) {
+				if ( afield != NULL && afield->field_string != NULL ) {
 					free( afield->field_string );
 					afield->field_string = NULL;
 				}
 /*
     AtomicParsley - main.cpp
 
-    AtomicParsley is GPL software; you can freely distribute, 
+    AtomicParsley is GPL software; you can freely distribute,
     redistribute, modify & use under the terms of the GNU General
     Public License; either version 2 or its successor.
 
     AtomicParsley is distributed under the GPL "AS IS", without
     any warranty; without the implied warranty of merchantability
     or fitness for either an expressed or implied particular purpose.
-		
-    Please see the included GNU General Public License (GPL) for 
+
+    Please see the included GNU General Public License (GPL) for
     your rights and further details; see the file COPYING. If you
     cannot, write to the Free Software Foundation, 59 Temple Place
     Suite 330, Boston, MA 02111-1307, USA.  Or www.fsf.org
 
     Copyright �2005-2007 puck_lock
-		
+
 		----------------------
     Code Contributions by:
-		
+
     * Mike Brancato - Debian patches & build support
 		* Brian Story - porting getopt & native Win32 patches
                                                                    */
 #define Meta_advisory            'V'
 #define Meta_stik                'S'
 #define Meta_description         'p'
+#define Meta_Rating			     0xCB
 #define Meta_longdescription     'j'
 #define Meta_TV_Network          'n'
 #define Meta_TV_ShowName         'H'
 
 #define OPT_OverWrite            'W'
 
+#if defined (WIN32)
+#define OPT_PreserveTimeStamps	 0xCA
+#endif
+
 #define ISO_Copyright            0xAA
 
 #define _3GP_Title               0xAB
 "                                           or set in an integer value with --stik value=(num)\n"
 "                                      Note: --stik Audiobook will change file extension to '.m4b'\n"
 "  --description      ,  -p   (str)    Sets the description on the \"desc\" atom\n"
+"  --Rating           ,       (str)    Sets the Rating on the \"rate\" atom\n"
 "  --longdesc         ,  -j   (str)    Sets the long description on the \"ldes\" atom\n"
 "  --TVNetwork        ,  -n   (str)    Sets the TV Network name on the \"tvnn\" atom\n"
 "  --TVShowName       ,  -H   (str)    Sets the TV Show name on the \"tvsh\" atom\n"
 "  --overWrite        ,  -W            Writes to temp file; deletes original, renames temp to original\n"
 "                                      If possible, padding will be used to update without a full rewrite.\n"
 "\n"
+#if defined (WIN32)
+"  --preserveTime                      Will overwrite the original file in place (--overWrite forcrd),\n"
+"                                      but will also keep the original file's timestamps intact.\n"
+"\n"
+#endif
 "  --DeepScan                          Parse areas of the file that are normally skipped (must be the 3rd arg)\n"
 "  --iPod-uuid                (num)    Place the ipod-required uuid for higher resolution avc video files\n"
 "                                      Currently, the only number used is 1200 - the maximum number of macro-\n"
 " standard' for ID3 allows multiple langauges for frames like COMM (comment) & USLT (lyrics). In mpeg-4\n"
 " this language setting is removed from the ID3 domain and exists in the mpeg-4 domain. That means that\n"
 " when an english and a spanish comment are set, 2 separate ID32 atoms are created, each with a tag & 1\n"
-" frame as in this example:\n" 
+" frame as in this example:\n"
 "       --ID3Tag COMM \"Primary\" --desc=AAA --ID3Tag COMM \"El Segundo\" UTF16LE lang=spa --desc=AAA\n"
 " See available frames with \"AtomicParsley --ID3frames-list\"\n"
 " See avilable imagetypes with \"AtomicParsley --imagetype-list\"\n"
 	pad_prefs.default_padding_size = DEFAULT_PADDING_LENGTH;
 	pad_prefs.minimum_required_padding_size = MINIMUM_REQUIRED_PADDING_LENGTH;
 	pad_prefs.maximum_present_padding_size = MAXIMUM_REQUIRED_PADDING_LENGTH;
-	
+
 	if (env_padding_prefs != NULL) {
 		if (env_padding_prefs[0] == 0x22 || env_padding_prefs[0] == 0x27) env_padding_prefs++;
 	}
 	char* env_pad_prefs_ptr = env_padding_prefs;
-	
+
 	while (env_pad_prefs_ptr != NULL) {
 		env_pad_prefs_ptr = strsep(&env_padding_prefs,":");
-		
+
 		if (env_pad_prefs_ptr == NULL) break;
-		
+
 		if (memcmp(env_pad_prefs_ptr, "DEFAULT_PAD=", 12) == 0) {
 			strsep(&env_pad_prefs_ptr,"=");
 			sscanf(env_pad_prefs_ptr, "%u", &pad_prefs.default_padding_size);
 		}
 	}
 	memcpy(basepath, filepath, (size_t)split_here);
-	
+
 	return;
 }
 
 void find_optional_args(char *argv[], int start_optindargs, uint16_t &packed_lang, bool &asUTF16, uint8_t &udta_container, uint8_t &trk_idx, int max_optargs) {
 	asUTF16 = false;
 	packed_lang = 5575; //und = 0x55C4 = 21956, but QTPlayer doesn't like und //eng =  0x15C7 = 5575
-	
+
 	for (int i= 0; i <= max_optargs-1; i++) {
 		if ( argv[start_optindargs + i] && start_optindargs + i <= total_args ) {
 			if ( memcmp(argv[start_optindargs + i], "lang=", 5) == 0 ) {
 				} else {
 					packed_lang = PackLanguage(argv[start_optindargs +i], 5);
 				}
-			
+
 			} else if ( memcmp(argv[start_optindargs + i], "UTF16", 5) == 0 ) {
 				asUTF16 = true;
 			} else if ( memcmp(argv[optind + i], "movie", 6) == 0 ) {
 			} else if ( memcmp(argv[optind + i], "track=", 6) == 0 ) {
 				char* track_index_str = argv[optind + i];
 				strsep(&track_index_str, "=");
-				sscanf(track_index_str, "%hhu", &trk_idx);
-				udta_container = SINGLE_TRACK_ATOM;	
+				sscanf(track_index_str, "%" PRIu8 "", &trk_idx);
+				udta_container = SINGLE_TRACK_ATOM;
 			} else if ( memcmp(argv[optind + i], "track", 6) == 0 ) {
 				udta_container = ALL_TRACKS_ATOM;
 			}
 void scan_ID3_optargs(char *argv[], int start_optargs, const char* &target_lang, uint16_t &packed_lang, uint8_t &char_encoding, char* meta_container, bool &multistring) {
 	packed_lang = 5575; //default ID32 lang is 'eng'
 	uint16_t i = 0;
-	
+
 	while (argv[start_optargs + i] != NULL) {
 		if ( argv[start_optargs + i] && start_optargs + i <= total_args ) {
-			
+
 			if ( memcmp(argv[start_optargs + i], "lang=", 5) == 0 ) {
 				if (!MatchLanguageCode(argv[start_optargs +i]+5) ) {
 					packed_lang = PackLanguage("und", 0);
 					packed_lang = PackLanguage(argv[start_optargs +i], 5);
 					target_lang = argv[start_optargs + i] + 5;
 				}
-			
+
 			} else if ( memcmp(argv[start_optargs + i], "UTF16LE", 8) == 0 ) {
 				char_encoding = TE_UTF16LE_WITH_BOM;
 			} else if ( memcmp(argv[start_optargs + i], "UTF16BE", 8) == 0 ) {
 				char_encoding = TE_UTF16BE_NO_BOM;
 			} else if ( memcmp(argv[start_optargs + i], "LATIN1", 7) == 0 ) {
 				char_encoding = TE_LATIN1;
-				
+
 			} else if ( memcmp(argv[optind + i], "root", 5) == 0 ) {
 				*meta_container = 0-FILE_LEVEL_ATOM;
 			} else if ( memcmp(argv[optind + i], "track=", 6) == 0 ) {
 				sscanf(track_index_str, "%hhu", meta_container);
 			}
 		}
-		
+
 		if (memcmp(argv[start_optargs + i], "-", 1) == 0) {
 			break; //we've hit another cli argument or deleting some frame
 		}
 	const char* ret_val = "";
 	uint16_t i = 0;
 	uint8_t arg_prefix_len = strlen(arg_string);
-	
+
 	while (argv[start_optargs + i] != NULL) {
 		if ( argv[start_optargs + i] && start_optargs + i <= total_args ) {
 			if (memcmp(arg_string, "compressed", 11) == 0 && memcmp(argv[start_optargs + i], "compressed", 11) == 0) {
 	if (argc == 1) {
 		fprintf (stdout,"%s\n", shortHelp_text); exit(0);
 	} else if (argc == 2 && ((strncmp(argv[1],"-v",2) == 0) || (strncmp(argv[1],"-version",2) == 0)) ) {
-	
+
 		ShowVersionInfo();
 		exit(0);
-		
+
 	} else if (argc == 2) {
 		if ( (strncmp(argv[1],"-help",5) == 0) || (strncmp(argv[1],"--help",6) == 0) || (strncmp(argv[1],"-h",5) == 0 ) ) {
 			fprintf(stdout, "%s\n", shortHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--longhelp", 10) == 0) || (strncmp(argv[1],"-longhelp", 9) == 0) || (strncmp(argv[1],"-Lh", 3) == 0) ) {
 			if (UnicodeOutputStatus == WIN32_UTF16) { //convert the helptext to utf16 to preserve � characters
 				int help_len = strlen(longHelp_text)+1;
 				wmemset(Lhelp_text, 0, help_len);
 				UTF8ToUTF16LE((unsigned char*)Lhelp_text, 2*help_len, (unsigned char*)longHelp_text, help_len);
 #if defined (_MSC_VER)
-				APar_unicode_win32Printout(Lhelp_text, longHelp_text);
+				APar_unicode_win32Printout(Lhelp_text, (char *) longHelp_text);
 #endif
 				free(Lhelp_text);
 			} else {
 				fprintf(stdout, "%s", longHelp_text);
 			}
 			exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--3gp-help", 10) == 0) || (strncmp(argv[1],"-3gp-help", 9) == 0) || (strncmp(argv[1],"--3gp-h", 7) == 0) ) {
 			fprintf(stdout, "%s\n", _3gpHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--ISO-help", 10) == 0) || (strncmp(argv[1],"--iso-help", 10) == 0) || (strncmp(argv[1],"-Ih", 3) == 0) ) {
 			fprintf(stdout, "%s\n", ISOHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--file-help", 11) == 0) || (strncmp(argv[1],"-file-help", 10) == 0) || (strncmp(argv[1],"-fh", 3) == 0) ) {
 			fprintf(stdout, "%s\n", fileLevelHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--uuid-help", 11) == 0) || (strncmp(argv[1],"-uuid-help", 10) == 0) || (strncmp(argv[1],"-uh", 3) == 0) ) {
 			fprintf(stdout, "%s\n", uuidHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--reverseDNS-help", 18) == 0) || (strncmp(argv[1],"-rDNS-help", 10) == 0) || (strncmp(argv[1],"-rh", 3) == 0) ) {
 			fprintf(stdout, "%s\n", rDNSHelp_text); exit(0);
-			
+
 		} else if ( (strncmp(argv[1],"--ID3-help", 10) == 0) || (strncmp(argv[1],"-ID3-help", 9) == 0) || (strncmp(argv[1],"-ID3h", 4) == 0) ) {
 			fprintf(stdout, "%s\n", ID3Help_text); exit(0);
-			
+
 		} else if ( memcmp(argv[1], "--genre-list", 12) == 0 ) {
 			ListGenresValues(); exit(0);
-			
+
 		} else if ( memcmp(argv[1], "--stik-list", 11) == 0 ) {
 			ListStikValues(); exit(0);
-			
+
 		} else if ( memcmp(argv[1], "--language-list", 16) == 0 ||
 								memcmp(argv[1], "--languages-list", 17) == 0 ||
 								memcmp(argv[1], "--list-language", 16) == 0 ||
 
 		} else if (memcmp(argv[1], "--ratings-list", 14) == 0) {
 			ListMediaRatings(); exit(0);
-			
+
 		} else if (memcmp(argv[1], "--ID3frames-list", 17) == 0) {
 			ListID3FrameIDstrings(); exit(0);
-		
+
 		} else if (memcmp(argv[1], "--imagetype-list", 17) == 0) {
 			List_imagtype_strings(); exit(0);
 		}
 	}
-	
+
 	if ( argc == 3 && (memcmp(argv[2], "--brands", 8) == 0 || memcmp(argv[2], "-brands", 7) == 0) ) {
 		APar_ExtractBrands(argv[1]); exit(0);
 	}
-	
+
 	int extr = 99;
 	total_args = argc;
 	char* ISObasemediafile = argv[1];
-	
+
 	TestFileExistence(ISObasemediafile, true);
-	
+
 	char* padding_options = getenv("AP_PADDING");
 	ExtractPaddingPrefs(padding_options);
-	
+
 	//it would probably be better to test output_file if provided & if --overWrite was provided.... probably only of use on Windows - and I'm not on it.
 	if (strlen(ISObasemediafile) + 11 > MAXPATHLEN) {
 		fprintf(stderr, "%c %s", '\a', "AtomicParsley error: filename/filepath was too long.\n");
 		exit(1);
 	}
-	
+
 	if ( argc > 3 && memcmp(argv[2], "--DeepScan", 10) == 0) {
 		deep_atom_scan = true;
 		APar_ScanAtoms(ISObasemediafile, true);
 	}
-	
+
 	while (1) {
 	static struct option long_options[] = {
 		{ "help",						  0,									NULL,						OPT_HELP },
 		{ "stik",             required_argument,  NULL,           Meta_stik },
     { "description",      required_argument,  NULL,           Meta_description },
     { "longdesc",      required_argument,  NULL,         Meta_longdescription },
+	{ "Rating",        required_argument,  NULL,           Meta_Rating },
     { "TVNetwork",        required_argument,  NULL,           Meta_TV_Network },
     { "TVShowName",       required_argument,  NULL,           Meta_TV_ShowName },
     { "TVEpisode",        required_argument,  NULL,           Meta_TV_Episode },
     { "TVEpisodeNum",     required_argument,  NULL,           Meta_TV_EpisodeNumber },
-    { "TVSeasonNum",      required_argument,  NULL,           Meta_TV_SeasonNumber },		
+    { "TVSeasonNum",      required_argument,  NULL,           Meta_TV_SeasonNumber },
 		{ "podcastFlag",      required_argument,  NULL,           Meta_podcastFlag },
 		{ "keyword",          required_argument,  NULL,           Meta_keyword },
 		{ "category",         required_argument,  NULL,           Meta_category },
 		{ "cnID",             required_argument,  NULL,           Meta_cnID },
 		{ "gapless",          required_argument,  NULL,           Meta_PlayGapless },
 		{ "sortOrder",        required_argument,  NULL,           Meta_SortOrder } ,
-		
+
 		{ "rDNSatom",         required_argument,  NULL,           Meta_ReverseDNS_Form },
 		{ "contentRating",    required_argument,  NULL,           Meta_rDNS_rating },
-		
+
 		{ "tagtime",          optional_argument,  NULL,						Meta_StandardDate },
 		{ "information",      required_argument,  NULL,           Meta_Information },
 		{ "url",              required_argument,  NULL,           Meta_URL },
 		{ "extract-uuids",    optional_argument,  NULL,           Opt_Extract_all_uuids },
 		{ "extract1uuid",     required_argument,  NULL,           Opt_Extract_a_uuid },
 		{ "iPod-uuid",        required_argument,  NULL,           Opt_Ipod_AVC_uuid },
-		
+
 		{ "freefree",         optional_argument,  NULL,           Opt_FreeFree },
 		{ "metaEnema",        0,                  NULL,						Metadata_Purge },
 		{ "manualAtomRemove", required_argument,  NULL,           Manual_atom_removal },
 		{ "output",           required_argument,  NULL,						OPT_OutputFile },
 		{ "preventOptimizing",0,                  NULL,						OPT_NoOptimize },
 		{ "overWrite",        0,                  NULL,						OPT_OverWrite },
-		
+#if defined (WIN32)
+		{ "preserveTime",        0,                  NULL,					OPT_PreserveTimeStamps },
+#endif
 		{ "ISO-copyright",    required_argument,  NULL,						ISO_Copyright },
-		
+
 		{ "3gp-title",        required_argument,  NULL,           _3GP_Title },
 		{ "3gp-author",       required_argument,  NULL,           _3GP_Author },
 		{ "3gp-performer",    required_argument,  NULL,           _3GP_Performer },
 		{ "3gp-copyright",    required_argument,  NULL,           _3GP_Copyright },
 		{ "3gp-album",        required_argument,  NULL,           _3GP_Album },
 		{ "3gp-year",         required_argument,  NULL,           _3GP_Year },
-		
+
 		{ "3gp-rating",       required_argument,  NULL,           _3GP_Rating },
 		{ "3gp-classification",  required_argument,  NULL,           _3GP_Classification },
 		{ "3gp-keyword",      required_argument,  NULL,           _3GP_Keyword },
 		{ "3gp-location",     required_argument,  NULL,           _3GP_Location },
-		
+
 		{ "ID3Tag",           required_argument,  NULL,           Meta_ID3v2Tag },
-		
+
 		{ "DeepScan",         0,                  &extr,          1 },
-		
+
 		{ 0, 0, 0, 0 }
 	};
-		
+
 	int c = -1;
-	int option_index = 0; 
-	
+	int option_index = 0;
+
 	c = getopt_long(argc, argv, "hTtEe:a:b:c:d:f:g:i:k:l:n:o:p:q::u:w:y:z:A:B:C:D:F:G:H:I:J:K:L:MN:QR:S:U:WXV:ZP 0xAA: 0xAB: 0xAC: 0xAD: 0xAE: 0xAF: 0xB0: 0xB1: 0xB2: 0xB3: 0xB4: 0xB5: 0xB6:", long_options, &option_index);
-	
+
 	if (c == -1) {
 		if (argc < 3 && argc > 2) {
 			APar_ScanAtoms(ISObasemediafile, true);
 		}
 		break;
 	}
-	
+
 	signal(SIGTERM, kill_signal);
 	signal(SIGINT,  kill_signal);
-	
+
 	switch(c) {
 		// "optind" represents the count of arguments up to and including its optional flag:
 
 		case '?': return 1;
-			
+
 		case OPT_HELP: {
 			fprintf (stdout,"%s", longHelp_text); return 0;
 		}
-					
+
 		case OPT_TEST: {
 			deep_atom_scan = true;
 			APar_ScanAtoms(ISObasemediafile, true);
 			}
 			break;
 		}
-		
+
 		case OPT_ShowTextData: {
 			if (argv[optind]) { //for utilities that write iTunes-style metadata into 3gp branded files
 				APar_ExtractBrands(ISObasemediafile);
 				deep_atom_scan=true;
 				APar_ScanAtoms(ISObasemediafile);
-				
+
 				APar_OpenISOBaseMediaFile(ISObasemediafile, true);
-				
+
 				if (memcmp(argv[optind], "+", 1) == 0) {
 					APar_Print_iTunesData(ISObasemediafile, NULL, PRINT_FREE_SPACE + PRINT_PADDING_SPACE + PRINT_USER_DATA_SPACE + PRINT_MEDIA_SPACE, PRINT_DATA );
 				} else {
 					fprintf(stdout, "---------------------------\n");
 					APar_Print_ISO_UserData_per_track();
-					
+
 					AtomicInfo* iTuneslistAtom = APar_FindAtom("moov.udta.meta.ilst", false, SIMPLE_ATOM, 0);
 					if (iTuneslistAtom != NULL) {
 						fprintf(stdout, "---------------------------\n  iTunes-style metadata tags:\n");
 					}
 					fprintf(stdout, "---------------------------\n");
 				}
-				
+
 			} else {
 				deep_atom_scan=true;
 				APar_ScanAtoms(ISObasemediafile);
 				APar_OpenISOBaseMediaFile(ISObasemediafile, true);
-				
+
 				if (metadata_style >= THIRD_GEN_PARTNER) {
 					APar_PrintUserDataAssests();
 				} else if (metadata_style == ITUNES_STYLE) {
 			APar_FreeMemory();
 			break;
 		}
-					
+
 		case OPT_ExtractPix: {
 			char* base_path=(char*)malloc(sizeof(char)*MAXPATHLEN+1);
 			memset(base_path, 0, MAXPATHLEN +1);
-			
+
 			GetBasePath( ISObasemediafile, base_path );
 			APar_ScanAtoms(ISObasemediafile);
 			APar_OpenISOBaseMediaFile(ISObasemediafile, true);
 			APar_Print_iTunesData(ISObasemediafile, base_path, 0, EXTRACT_ARTWORK); //exportPix to stripped ISObasemediafile path
 			APar_OpenISOBaseMediaFile(ISObasemediafile, false);
-			
+
 			free(base_path);
 			base_path = NULL;
 			break;
 		}
-		
+
 		case OPT_ExtractPixToPath: {
 			APar_ScanAtoms(ISObasemediafile);
 			APar_OpenISOBaseMediaFile(ISObasemediafile, true);
 			APar_OpenISOBaseMediaFile(ISObasemediafile, false);
 			break;
 		}
-				
+
 		case Meta_artist : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "artist") ) {
 			APar_Unified_atom_Put(artistData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_songtitle : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "title") ) {
 				break;
 			}
-			
+
 			AtomicInfo* titleData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�nam.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(titleData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_album : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "album") ) {
 				break;
 			}
-			
+
 			AtomicInfo* albumData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�alb.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(albumData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_genre : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "genre") ) {
 				break;
 			}
-			
+
 			APar_MetaData_atomGenre_Set(optarg);
 			break;
 		}
-				
+
 		case Meta_tracknum : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "track number") ) {
 				break;
 			}
-			
+
 			uint16_t pos_in_total = 0;
-			uint16_t the_total = 0; 
+			uint16_t the_total = 0;
 			if (strrchr(optarg, '/') != NULL) {
 
 				char* duplicate_info = optarg;
 			} else {
 				sscanf(optarg, "%" SCNu16, &pos_in_total);
 			}
-			
+
 			AtomicInfo* tracknumData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.trkn.data", optarg, AtomFlags_Data_Binary);
 			//tracknum: [0, 0, 0, 0,   0, 0, 0, pos_in_total, 0, the_total, 0, 0]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
 			APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
 			APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
 			break;
 		}
-		
+
 		case Meta_disknum : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "disc number") ) {
 				break;
 			}
-			
+
 			uint16_t pos_in_total = 0;
 			uint16_t the_total = 0;
 			if (strrchr(optarg, '/') != NULL) {
-				
+
 				char* duplicate_info = optarg;
 				char* item_stat = strsep(&duplicate_info,"/");
 				sscanf(item_stat, "%" SCNu16, &pos_in_total);
 				item_stat = strsep(&duplicate_info,"/");
 				sscanf(item_stat, "%" SCNu16, &the_total);
-			
+
 			} else {
 				sscanf(optarg, "%" SCNu16, &pos_in_total);
 			}
-			
+
 			AtomicInfo* disknumData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.disk.data", optarg, AtomFlags_Data_Binary);
 			//disknum: [0, 0, 0, 0,   0, 0, 0, pos_in_total, 0, the_total]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
 			APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
 			APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, the_total, 16);
 			break;
 		}
-		
+
 		case Meta_comment : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "comment") ) {
 				break;
 			}
-			
+
 			AtomicInfo* commentData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�cmt.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(commentData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_year : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "year") ) {
 				break;
 			}
-			
+
 			AtomicInfo* yearData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�day.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(yearData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_lyrics : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "lyrics") ) {
 				break;
 			}
-			
+
 			AtomicInfo* lyricsData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�lyr.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(lyricsData_atom, optarg, UTF8_iTunesStyle_Unlimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_composer : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "composer") ) {
 				break;
 			}
-			
+
 			AtomicInfo* composerData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�wrt.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(composerData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_copyright : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "copyright") ) {
 				break;
 			}
-			
+
 			AtomicInfo* copyrightData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.cprt.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(copyrightData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_grouping : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "grouping") ) {
 				break;
 			}
-			
+
 			AtomicInfo* groupingData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�grp.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(groupingData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_compilation : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "compilation") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "false", 5) == 0 || strlen(optarg) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.cpil.data", VERSIONED_ATOM, 0);
 			} else {
 			}
 			break;
 		}
-		
+
 		case Meta_hdvideo : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "hdvideo") ) {
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "BPM") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "0", 1) == 0 || strlen(optarg) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.tmpo.data", VERSIONED_ATOM, 0);
 			} else {
 			}
 			break;
 		}
-		
+
 		case Meta_advisory : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "content advisory") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "remove", 6) == 0 || strlen(optarg) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.rtng.data", VERSIONED_ATOM, 0);
 			} else {
 			}
 			break;
 		}
-		
+
 		case Meta_artwork : { //handled differently: there can be multiple "moov.udta.meta.ilst.covr.data" atoms
 			char* env_PicOptions = getenv("PIC_OPTIONS");
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "coverart") ) {
 				break;
 			}
-			
+
 			APar_MetaData_atomArtwork_Set(optarg, env_PicOptions);
 			break;
 		}
-				
+
 		case Meta_stik : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "'stik'") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "remove", 6) == 0 || strlen(optarg) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.stik.data", VERSIONED_ATOM, 0);
 			} else {
 				uint8_t stik_value = 0;
-				
+
 				if (memcmp(optarg, "value=", 6) == 0) {
 					char* stik_val_str_ptr = optarg;
 					strsep(&stik_val_str_ptr,"=");
-					sscanf(stik_val_str_ptr, "%hhu", &stik_value);
+					sscanf(stik_val_str_ptr, "%" PRIu8 "", &stik_value);
 				} else {
 					stiks* return_stik = MatchStikString(optarg);
 					if (return_stik != NULL) {
 			}
 			break;
 		}
-		
+
 		case Meta_EncodingTool : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "encoding tool") ) {
 				break;
 			}
-			
+
 			AtomicInfo* encodingtoolData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�too.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(encodingtoolData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "encoded by") ) {
 				break;
 			}
-			
+
 			AtomicInfo* encodedbyData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.�enc.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(encodedbyData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_apID : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "Account Name") ) {
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "description") ) {
 				break;
 			}
-			
+
 			AtomicInfo* descriptionData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.desc.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(descriptionData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "longdesc") ) {
 				break;
 			}
-			
+
 			AtomicInfo* descriptionData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.ldes.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(descriptionData_atom, optarg, UTF8_iTunesStyle_Unlimited, 0, 0);
 			break;
 		}
-			
+
+		case Meta_Rating : {
+			APar_ScanAtoms(ISObasemediafile);
+			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "Rating") ) {
+				break;
+			}
+
+			AtomicInfo* ratingData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.rate.data", optarg, AtomFlags_Data_Text);
+			APar_Unified_atom_Put(ratingData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
+			break;
+		}
+
 		case Meta_TV_Network : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "TV Network") ) {
 				break;
 			}
-			
+
 			AtomicInfo* tvnetworkData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.tvnn.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(tvnetworkData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_TV_ShowName : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "TV Show name") ) {
 				break;
 			}
-			
+
 			AtomicInfo* tvshownameData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.tvsh.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(tvshownameData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_TV_Episode : { //if the show "ABC Lost 209", its "209"
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "TV Episode string") ) {
 				break;
 			}
-			
+
 			AtomicInfo* tvepisodeData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.tven.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(tvepisodeData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_TV_SeasonNumber : { //if the show "ABC Lost 209", its 2; integer 2 not char "2"
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "TV Season") ) {
 				break;
 			}
-			
+
 			uint16_t data_value = 0;
 			sscanf(optarg, "%" SCNu16, &data_value );
-			
+
 			AtomicInfo* tvseasonData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.tvsn.data", optarg, AtomFlags_Data_UInt);
 			//season is [0, 0, 0, 0,   0, 0, 0, data_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
 			APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
 			APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, data_value, 16);
 			break;
 		}
-		
+
 		case Meta_TV_EpisodeNumber : { //if the show "ABC Lost 209", its 9; integer 9 (0x09) not char "9"(0x39)
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "TV Episode number") ) {
 				break;
 			}
-			
+
 			uint16_t data_value = 0;
 			sscanf(optarg, "%" SCNu16, &data_value );
-			
+
 			AtomicInfo* tvepisodenumData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.tves.data", optarg, AtomFlags_Data_UInt);
 			//episodenumber is [0, 0, 0, 0,   0, 0, 0, data_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
 			APar_Unified_atom_Put(tvepisodenumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "iTunes Catalog ID") ) {
 				break;
 			}
-			
+
 			uint32_t data_value = 0;
 			sscanf(optarg, "%" SCNu32, &data_value );
-			
+
 			AtomicInfo* cnIDData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.cnID.data", optarg, AtomFlags_Data_UInt);
 			//episodenumber is [0, 0, 0, 0,   0, 0, 0, data_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
 			APar_Unified_atom_Put(cnIDData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, data_value, 32);
 			break;
 		}
-		
+
 		case Meta_album_artist : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "album artist") ) {
 				break;
 			}
-			
+
 			AtomicInfo* albumartistData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.aART.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(albumartistData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_podcastFlag : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "podcast flag") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "false", 5) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.pcst.data", VERSIONED_ATOM, 0);
 			} else {
 				AtomicInfo* podcastFlagData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.pcst.data", optarg, AtomFlags_Data_UInt);
 				APar_Unified_atom_Put(podcastFlagData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 1, 8); //a hard coded uint8_t of: 1 denotes podcast flag
 			}
-			
+
 			break;
 		}
-		
+
 		case Meta_keyword : {    //TODO to the end of iTunes-style metadata & uuid atoms
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "keyword") ) {
 				break;
 			}
-			
+
 			AtomicInfo* keywordData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.keyw.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(keywordData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_category : { // see http://www.apple.com/itunes/podcasts/techspecs.html for available categories
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "category") ) {
 				break;
 			}
-			
+
 			AtomicInfo* categoryData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.catg.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(categoryData_atom, optarg, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_podcast_URL : { // usually a read-only value, but useful for getting videos into the 'podcast' menu
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "podcast URL") ) {
 				break;
 			}
-			
+
 			AtomicInfo* podcasturlData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.purl.data", optarg, AtomFlags_Data_Binary);
 			APar_Unified_atom_Put(podcasturlData_atom, optarg, UTF8_iTunesStyle_Binary, 0, 0);
 			break;
 		}
-		
+
 		case Meta_podcast_GUID : { // Global Unique IDentifier; it is *highly* doubtful that this would be useful...
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "podcast GUID") ) {
 				break;
 			}
-			
+
 			AtomicInfo* globalidData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.egid.data", optarg, AtomFlags_Data_Binary);
 			APar_Unified_atom_Put(globalidData_atom, optarg, UTF8_iTunesStyle_Binary, 0, 0);
 			break;
 		}
-		
+
 		case Meta_PurchaseDate : { // might be useful to *remove* this, but adding it... although it could function like id3v2 tdtg...
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "purchase date") ) {
 			} else {
 				purd_time = optarg;
 			}
-			
+
 			AtomicInfo* globalIDData_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.purd.data", optarg, AtomFlags_Data_Text);
 			APar_Unified_atom_Put(globalIDData_atom, purd_time, UTF8_iTunesStyle_256glyphLimited, 0, 0);
 			if (free_memory) {
 			}
 			break;
 		}
-		
+
 		case Meta_PlayGapless : {
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "gapless playback") ) {
 				break;
 			}
-			
+
 			if (strncmp(optarg, "false", 5) == 0 || strlen(optarg) == 0) {
 				APar_RemoveAtom("moov.udta.meta.ilst.pgap.data", VERSIONED_ATOM, 0);
 			} else {
 			}
 			break;
 		}
-		
+
 		case Meta_SortOrder : {
 			AtomicInfo* sortOrder_atom = NULL;
 			APar_ScanAtoms(ISObasemediafile);
 			if ( !APar_assert(metadata_style == ITUNES_STYLE, 1, "sort order tags") ) {
 				break;
 			}
-			
+
 			if (argv[optind] == NULL) {
 				fprintf(stdout, "AP warning, skipping setting the sort order %s tag\n", optarg);
 				break;
 			}
-			
+
 			if ( memcmp(optarg, "name", 5) == 0 ) {
-				sortOrder_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.sonm.data", argv[optind], AtomFlags_Data_Text);			
+				sortOrder_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.sonm.data", argv[optind], AtomFlags_Data_Text);
 			} else if ( memcmp(optarg, "artist", 7) == 0 ) {
 				sortOrder_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.soar.data", argv[optind], AtomFlags_Data_Text);
 			} else if ( memcmp(optarg, "albumartist", 12) == 0 ) {
 				sortOrder_atom = APar_MetaData_atom_Init("moov.udta.meta.ilst.sosn.data", argv[optind], AtomFlags_Data_Text);
 			}
 			APar_Unified_atom_Put(sortOrder_atom, argv[optind], UTF8_iTunesStyle_256glyphLimited, 0, 0);
-			
+
 			break;
 		}
-		
+
 		//uuid atoms
-		
+
 		case Meta_StandardDate : {
 			APar_ScanAtoms(ISObasemediafile);
 			char* formed_time = (char *)malloc(sizeof(char)*110);
 					APar_StandardTime(formed_time);
 				}
 			}
-			
+
 			AtomicInfo* tdtgUUID = APar_uuid_atom_Init("moov.udta.meta.uuid=%s", "tdtg", AtomFlags_Data_Text, formed_time, false);
 			APar_Unified_atom_Put(tdtgUUID, formed_time, UTF8_iTunesStyle_Unlimited, 0, 0);
 			free(formed_time);
 			break;
 		}
-		
+
 		case Meta_URL : {
 			APar_ScanAtoms(ISObasemediafile);
 			AtomicInfo* urlUUID = APar_uuid_atom_Init("moov.udta.meta.uuid=%s", "�url", AtomFlags_Data_Text, optarg, false);
 			APar_Unified_atom_Put(urlUUID, optarg, UTF8_iTunesStyle_Unlimited, 0, 0);
 			break;
 		}
-		
+
 		case Meta_Information : {
 			APar_ScanAtoms(ISObasemediafile);
 			AtomicInfo* infoUUID = APar_uuid_atom_Init("moov.udta.meta.uuid=%s", "�inf", AtomFlags_Data_Text, optarg, false);
 			char* uuid_file_extn = NULL;
 			char* uuid_file_mimetype = NULL;
 //			char* uuid_file_filename = NULL;
-			
+
 			// a uuid in AP is a version 5 uuid created by getting a sha1 hash
 			// of a string (the atom name) in a namespace ('AP.sf.net'). This
 			// is guaranteed to be reproducible, so later it can be verified
 						uuid_file_path = argv[optind + 1];
 						//get the file extension/suffix of the file to embed
 						uuid_file_extn = strrchr(uuid_file_path, '.'); //'.' inclusive; say goodbye to AP-0.8.8.tar.bz2
-						
+
 //#ifdef WIN32
 //#define path_delim '\'
 //#else
 					}
 				}
 			}
-			
+
 			AtomicInfo* genericUUID = APar_uuid_atom_Init("moov.udta.meta.uuid=%s", optarg, uuid_dataType, argv[optind +1], true);
-			
+
 			if (uuid_dataType == AtomFlags_Data_uuid_binary && genericUUID != NULL) {
 				TestFileExistence(uuid_file_path, true);
-				
+
 //format for a uuid atom set by AP:
 //4 bytes     - atom length as uin32_t
 //4 bytes     - atom name as iso 8859-1 atom name as a 4byte string set to 'uuid'
 		//X bytes - utf8 string holding the MIME-type, null terminated
 		//4 bytes - length of the attached binary data/file length
 		//X bytes - binary data
-				
+
 				uint32_t extn_len = strlen(uuid_file_extn)+1; //+1 for the trailing 1 byte NULL terminator
 				uint64_t file_len = findFileSize(uuid_file_path);
-				
+
 				APar_MetaData_atom_QuickInit(genericUUID->AtomicNumber, uuid_dataType, 20, extn_len + desc_len + file_len + 100);
 				genericUUID->AtomicClassification = EXTENDED_ATOM; //it gets reset in QuickInit Above; force its proper setting
-				
+
 				if (uuid_file_description == NULL || desc_len == 0) {
 					APar_Unified_atom_Put(genericUUID, "[none]", UTF8_3GP_Style, 7, 32); //sets 4bytes desc_len, then 7bytes description (forced to "[none]"=6 + 1 byte NULL =7)
 				} else {
 					APar_Unified_atom_Put(genericUUID, uuid_file_description, UTF8_3GP_Style, desc_len, 32); //sets 4bytes desc_len, then Xbytes description (in that order)
 				}
-				
+
 				APar_Unified_atom_Put(genericUUID, uuid_file_extn, UTF8_3GP_Style, extn_len, 8); //sets 1bytes desc_len, then Xbytes file extension string (in that order)
-				
+
 				if (uuid_file_mimetype == NULL || mime_len == 0) {
 					APar_Unified_atom_Put(genericUUID, "none", UTF8_3GP_Style, 5, 8); //sets 4bytes desc_len, then 5bytes description (forced to "none" + 1byte null)
 				} else {
 					APar_Unified_atom_Put(genericUUID, uuid_file_mimetype, UTF8_3GP_Style, mime_len, 8); //sets 1 byte mime len, then Xbytes mime type
 				}
-				
+
 				FILE* uuid_binfile = APar_OpenFile(uuid_file_path, "rb");
 				APar_Unified_atom_Put(genericUUID, NULL, UTF8_3GP_Style, file_len, 32);
 				//store the data directly on the atom in AtomicData
 				uint32_t bin_bytes_read = APar_ReadFile(genericUUID->AtomicData + (genericUUID->AtomicLength - 32), uuid_binfile, file_len);
 				genericUUID->AtomicLength += bin_bytes_read;
 				fclose(uuid_binfile);
-				
+
 			} else { //text type
 				APar_Unified_atom_Put(genericUUID, argv[optind +1], UTF8_iTunesStyle_Unlimited, 0, 0);
 			}
 
 			break;
 		}
-		
+
 		case Opt_Extract_all_uuids : {
 			APar_ScanAtoms(ISObasemediafile);
 			char* output_path = NULL;
 			APar_OpenISOBaseMediaFile(ISObasemediafile, true);
 			APar_Print_APuuid_atoms(ISObasemediafile, output_path, EXTRACT_ALL_UUID_BINARYS);
 			APar_OpenISOBaseMediaFile(ISObasemediafile, false);
-			
+
 			exit(0);//never gets here
 			break;
 		}
-		
+
 		case Opt_Extract_a_uuid : {
 			APar_ScanAtoms(ISObasemediafile);
-			
+
 			char* uuid_path = (char*)calloc(1, sizeof(char)*256+1);
 			char* uuid_binary_str = (char*)calloc(1, sizeof(char)*20+1);
 			char uuid_4char_name[16]; memset(uuid_4char_name, 0, 16);
 			AtomicInfo* extractionAtom = NULL;
-			
+
 			UTF8Toisolat1((unsigned char*)&uuid_4char_name, 4, (unsigned char*)optarg, strlen(optarg) );
 			APar_generate_uuid_from_atomname(uuid_4char_name, uuid_binary_str);
-			
+
 			//this will only append (and knock off) %s (anything) at the end of a string
 			uint16_t path_len = strlen("moov.udta.meta.uuid=%s");
 			memcpy(uuid_path, "moov.udta.meta.uuid=%s", path_len-2);
 			memcpy(uuid_path + (path_len-2), uuid_binary_str, 16);
-			
+
 			extractionAtom = APar_FindAtom(uuid_path, false, EXTENDED_ATOM, 0, true);
 			if (extractionAtom != NULL) {
 				APar_OpenISOBaseMediaFile(ISObasemediafile, true);
 				APar_Extract_uuid_binary_file(extractionAtom, ISObasemediafile, NULL);
 				APar_OpenISOBaseMediaFile(ISObasemediafile, false);
 			}
-