Gamestudio Links
Zorro Links
Newest Posts
Data from CSV not parsed correctly
by EternallyCurious. 04/18/24 10:45
StartWeek not working as it should
by Zheka. 04/18/24 10:11
folder management functions
by VoroneTZ. 04/17/24 06:52
lookback setting performance issue
by 7th_zorro. 04/16/24 03:08
zorro 64bit command line support
by 7th_zorro. 04/15/24 09:36
Zorro FIX plugin - Experimental
by flink. 04/14/24 07:48
Zorro FIX plugin - Experimental
by flink. 04/14/24 07:46
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
4 registered members (Quad, AndrewAMD, EternallyCurious, 7th_zorro), 511 guests, and 1 spider.
Key: Admin, Global Mod, Mod
Newest Members
EternallyCurious, 11honza11, ccorrea, sakolin, rajesh7827
19046 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 1 of 2 1 2
Inserting data in the middle of a file #251678
02/14/09 15:44
02/14/09 15:44
Joined: Feb 2008
Posts: 3,232
Australia
EvilSOB Offline OP
Expert
EvilSOB  Offline OP
Expert

Joined: Feb 2008
Posts: 3,232
Australia
ANNOUNCEMENT - CODE HAS BEEN RE-IMAGINED
Due to new developments/discoveries, this code has been seriously overhauled.

Newer FASTER code is now in place, almost all functions usage/parameters have
remained the same and two new functions have been added.
Performance/response times have now also been provided.


Of late, there had been a discussion smouldering in the Future forum about our ability to insert text into the middle
of a file. Some people are after this functionality to be added to the engine, but JCL makes it seem unlikely due to
complexity and lack of nececessity and/or interest.

FEAR NO MORE !
I have spent the last week coding the following include to give everyone this missing functionality.

Have a quick scroll through and you'll see theres plenty of documentation in there. It just looks a bit mis-aligned
through the forum display, but just cut and paste into SED and everything will line up neatly.

Please feel free to let me know of any bugs or problems, and suggestions are welcome.
Thank you all.

Code:
#ifndef File_Open_RW_h
#define File_Open_RW_h
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//		FILE_OPEN_RW.H
//
//		Library of 3DGS-like functiona filling some gaps in updating data MID-file.
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//		Largely equivalent to standard file_open_write() and file_open_append() 
//		functionality but adds the EXTRA ability to insert STRING, VAR, ASC or buffer data 
//		at mid-file positions, and to read buffer data blocks from mid-file, and to delete
//		specific blocks of data from mid-file.
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//		Author	:	EvilSOB
//		Updated	: 	18-02-2009
//
//		Requirements:	Acknex.h
//
//
//		Notes:
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//		FUNCTIONS
//
//=======================================================================================
//		file_open_RW(STRING* name);
//---------------------------------------------------------------------------------------
//		Opens a file for reading and writing additional content at any point. 
//		If the file does not exist, it is created.
//		The function returns a file handle - that is a unique number to identify the file. 
//		The file handle is used by other functions to access that file. 
//---------------------------------------------------------------------------------------
//		Parameters:
//			name	- file name with or without path, STRING* or char*. 
//---------------------------------------------------------------------------------------
//		Returns:
//			File handle(type VAR), or NULL if the file could not be opened. 
//
//
//
//
//=======================================================================================
//		file_close_RW(var handle);
//---------------------------------------------------------------------------------------
//		Closes the file with the given handle. A file must be closed before other programs
//			can access it, or before it can be opened again in a different mode. As soon as
//			the file is closed, the handle becomes invalid.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle of the closing file.
//---------------------------------------------------------------------------------------
//		NOTE: 
//			Using lite-c file_close() on a file_open_RW() file works fine but wastes a very
//				small amount of memory. (up to 500 bytes, no more)
//
//
//
//
//=======================================================================================
//		file_void_insert(var handle, void* buffer, var size, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes the given buffer into the file with the given handle. The file must be have
//			been opened with file_open_RW(). 
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			buffer	- Void Pointer to a preallocated buffer.
//			size 		- The length of the block to be written.
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//			False	- file update failed. Due to calculated offset outside file bounds.
//			False	- file update failed. Due to invalid buffer pointer.
//			False	- file update failed. Due to invalid buffer length.
//
//
//
//
//=======================================================================================
//		file_str_insert(var handle, STRING* text, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes the given string into the file with the given handle. The file must be have
//			been opened with file_open_RW(). The string is unmodified, i.e. special 
//			sequences like '\n' are not converted. 
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			text		- Character string to be written into the file 
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//			False	- file update failed. Due to calculated offset outside file bounds.
//
//
//
//
//=======================================================================================
//		file_var_insert(var handle, var number, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes the given number or variable into the file with the given handle. The file
//			must have been opened with file_open_RW(). If the number has a decimal between
//			.001 and .999, the number is then written with 3 decimals, ending by a blank.
//			Otherwise the integer is written with no decimals, again ending by a blank.
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			number	- Value to be written into the file as a string 
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//			False	- file update failed. Due to calculated offset outside file bounds.
//
//
//
//
//=======================================================================================
//		file_asc_insert(var handle, var number, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes a single byte given by the number or variable (0..255) into the file with 
//		the given handle. The file must have been opened with file_open_RW(). 
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			number	- Number between 0 and 255.
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//			False	- file update failed. Due to calculated offset outside file bounds.
//
//
//
//
//=======================================================================================
//		file_bytes_remove(var handle, var cut_qty, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Removes cut_qty number of bytes from the the file with the given handle. The file 
//			must have been opened with file_open_RW(). 
//		After data-removal, the read pointer is placed at the position of the removed data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			cut_qty	- Quantity of bytes to be "cut" from the middle of the file.
//			offset	- Cut position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//			False	- file update failed. Due to calculated offset outside file bounds.
//
//
//
//
//=======================================================================================
//		void* file_void_read(var handle, var read_qty, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Reads read_qty number of bytes from the the file with the given handle. The file 
//			must have been opened with file_open_RW(). 
//		After data-retrieval, the read pointer is placed at the end of the read data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			read_qty	- Quantity of bytes to be read from the middle of the file.
//			offset	- Cut position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			VOID*	- Void pointer to the retrieved data. Should be released using free(...);
//			NULL	- file update failed. Due to invalid handle.
//			NULL	- file update failed. Due to file not opened with file_open_RW.
//			NULL	- file update failed. Due to calculated offset outside file bounds.
//
//
//
//
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//
//
#define Max_RW_files	25		//MAXIMUM file_insert files allowed open AT ANY ONE TIME
STRING*	RW_filename[Max_RW_files];
var 		RW_file[Max_RW_files];
//
function file_open_RW_startup()		//initialise empty File tracking table
{	var f; for(f=0; f<Max_RW_files; f++)	RW_filename[f] = RW_file[f] = NULL;	}
//
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//
function file_open_RW(STRING* filename)		//open file for read/write capability
{	var f; for(f=0; f<Max_RW_files; f++)			//look for available slot
	{	if(RW_file[f]==NULL)									//in tracking table
		{	RW_filename[f] = str_create(_chr(filename));			//create entry 
			RW_file[f] 	 = file_open_read(filename);				//in vacant
			break;			}		}												//slot
	if(f==Max_RW_files)	return(NULL);	//no space in table to open new file
	return(RW_file[f]);			//return pointer to new insert-capable file
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_close_RW(var *file)			//close insert-capable entry in tracking table
{	if(*file==NULL)	return(false);	//not a valid file pointer
	var f; for(f=0; f<Max_RW_files; f++)	//look for table entry 
	{	if(RW_file[f]==*file)	break;		}		//that matches pointer
	if(f<Max_RW_files)			//clear table entry
	{	RW_file[f] = NULL;				//for re-use 
		str_remove(RW_filename[f]);	//and release memory 
		RW_filename[f] = NULL;			}	//used by string
	file_close(*file);		//close file whether it was in the table or not.
	return(true);
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_void_insert(var *file, void* block, var block_len, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	if(block==NULL)		return(false);	//not a valid block pointer
	if(block_len<00)	return(false);	//not a valid block length
	var f; for(f=0; f<Max_RW_files; f++)		//look for table entry
	{	if(RW_file[f]==*file)	break;		}			//that matches pointer
	if(f==Max_RW_files)	return(false);	//not an RW-capable file
	if(mode == 3)
		offset += file_length(RW_file[f]);				//offset relates to end of file
	else if(mode == 1)
		offset += file_seek(RW_file[f], NULL, 4);		//offset relates to current position
	else	//mode==0
		offset += 0;											//offset relates to beginning of file
	int bytepos = offset;	//define position that changes take place at
	if(bytepos<0)									return(false);		//invalid start position
	if(bytepos>file_length(RW_file[f]))		return(false);		//invalid start position
	file_close(RW_file[f]);		//close original file
	long fsize = 0;	long block_size = block_len;	//define file and block length storage
	long buffer0 = (void*)file_load(_chr(RW_filename[f]), NULL, &fsize);	//read whole file
	long buffer1 = (void*)malloc(fsize + block_size);	//create new file workspace
	memcpy( buffer1 , buffer0, bytepos);	//copy across pre-insert data
	memcpy( buffer1+bytepos , block, block_size);	//copy across insert data
	memcpy( buffer1+bytepos+block_size , buffer0+bytepos, fsize-bytepos); //copy remaining
   file_save(RW_filename[f], (void*)buffer1, fsize + block_len);	//overwite old file
	file_load(NULL, (void*)buffer0, NULL);		free(buffer1);		//free file buffers
	RW_file[f] = file_open_read(RW_filename[f]);	//re-open it as RW-capable
	file_seek(RW_file[f], bytepos, 0);		//re-position read position to after insert
	*file = RW_file[f];		//reset pointer to file to calling function
	return(true);	//return successful status	
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_str_insert(var *file, STRING* text, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	if(text==NULL)		return(false);	//not a valid STRING pointer
	var Results = file_void_insert(*file, text.chars, str_len(text)+1, offset, mode);
	return(Results);		//inform caller of sucess/failure
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_asc_insert(var *file, var num, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	STRING* tmpStr = " ";		//temp space for to-be-written data
	str_for_asc(tmpStr, num);		//convert ASC value into CHAR character for writing
	var Results = file_void_insert(*file, tmpStr.chars, 1, offset, mode);	//write char
	str_remove(tmpStr);			//remove/free temp spaces from has-be-written data
	return(Results);		//inform caller of sucess/failure
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_var_insert(var *file, var num, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	STRING* tmpStr = ".............";		//temp space for to-be-written data
	str_for_num(tmpStr, num);		//convert number value into STRING for writing
	var Results = file_void_insert(*file, tmpStr.chars, tmpStr.length, offset, mode);
	str_remove(tmpStr);			//remove/free temp spaces from has-be-written data
	return(Results);		//inform caller of sucess/failure
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_bytes_remove(var *file, var cut_qty, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	var f; for(f=0; f<Max_RW_files; f++)		//look for table entry
	{	if(RW_file[f]==*file)	break;		}			//that matches pointer
	if(f==Max_RW_files)	return(false);	//not an RW-capable file
	if(mode == 3)
		offset += file_length(RW_file[f]);				//offset relates to end of file
	else if(mode == 1)
		offset += file_seek(RW_file[f], NULL, 4);		//offset relates to current position
	else	//mode==0
		offset += 0;											//offset relates to beginning of file
	long bytepos = offset;	//define position that changes take place at
	if(bytepos<0)									return(false);		//invalid start position
	if(bytepos>=file_length(RW_file[f]))	return(false);		//invalid start position
	if((bytepos+cut_qty)>file_length(RW_file[f]))		//reduce overshooting
		cut_qty = file_length(RW_file[f]) - bytepos;		//of cut_qty
	file_close(RW_file[f]);		//close original file
	long fsize = 0;	long cut_size = cut_qty;	//define file size and cut size variables
	long buffer0 = (void*)file_load(_chr(RW_filename[f]), NULL, &fsize);	//read whole file
	memcpy( buffer0+bytepos , buffer0+bytepos+cut_size, fsize-bytepos);  //copy remaining
   file_save(RW_filename[f], (void*)buffer0, fsize - cut_size);	//overwite old file
	file_load(NULL, (void*)buffer0, NULL);		//free file buffer
	RW_file[f] = file_open_read(RW_filename[f]);	//re-open it as RW-capable
	file_seek(RW_file[f], bytepos, 0);		//re-position read position to after deletion
	*file = RW_file[f];		//reset pointer to file to calling function
	return(true);	//return successful status	
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
void* file_void_read(var *file, var read_qty, var offset, var mode)
{	if(*file==NULL)	return((void*)NULL);	//not a valid file pointer
	if(read_qty<=0)	return((void*)NULL);	//not a valid block length
	var f; for(f=0; f<Max_RW_files; f++)		//look for table entry
	{	if(RW_file[f]==*file)	break;		}			//that matches pointer
	if(f==Max_RW_files)	return((void*)NULL);	//not an RW-capable file
	if(mode == 3)
		offset += file_length(RW_file[f]);				//offset relates to end of file
	else if(mode == 1)
		offset += file_seek(RW_file[f], NULL, 4);		//offset relates to current position
	else	//mode==0
		offset += 0;											//offset relates to beginning of file
	long bytepos = offset;	//define position that read takes place at
	if(bytepos<0)									return((void*)NULL);   //invalid start position
	if(bytepos>=file_length(RW_file[f]))	return((void*)NULL);   //invalid start position
	long fsize = 0;	long read_size = read_qty;	//define file size and read sizes
	long buffer0 = (void*)file_load(_chr(RW_filename[f]), NULL, &fsize);	//read whole file
	long buffer1 = (void*)malloc(read_size);	//create out-block workspace
	memcpy( buffer1, buffer0+bytepos, read_size);  //copy required data
	file_load(NULL, (void*)buffer0, NULL);		//free file-read buffer
	return((void*)(buffer1));	//return pointer to retrieved block	
}
//
//
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//
#endif	// File_Open_RW_h


Here is the performance info, Ive listed the speed my old loop-based code ran at, and the speed of this code.
It show the response times on an Athalon 64x2 6000, 2gig Ram machine, with a range of file sizes.
There is only two tests per file per code, as those two listed functions do all the work.
Code:
FileSize   function tested      NEW code time        Old code time
=====================================================================================
1K       file_bytes_remove()   (new)=0.004984 secs   (old)=0.001148 secs
         file_void_insert()    (new)=0.004852 secs   (old)=0.000660 secs
-------------------------------------------------------------------------------------
5K       file_bytes_remove()   (new)=0.005016 secs   (old)=0.002321 secs
         file_void_insert()    (new)=0.004893 secs   (old)=0.001619 secs
-------------------------------------------------------------------------------------
10K      file_bytes_remove()   (new)=0.005029 secs   (old)=0.003211 secs
         file_void_insert()    (new)=0.004913 secs   (old)=0.002710 secs
-------------------------------------------------------------------------------------
50K      file_bytes_remove()   (new)=0.005135 secs   (old)=0.011177 secs
         file_void_insert()    (new)=0.005003 secs   (old)=0.011398 secs
-------------------------------------------------------------------------------------
100K     file_bytes_remove()   (new)=0.005274 secs   (old)=0.021067 secs
         file_void_insert()    (new)=0.005089 secs   (old)=0.022597 secs
-------------------------------------------------------------------------------------
500K     file_bytes_remove()   (new)=0.008007 secs   (old)=0.098530 secs
         file_void_insert()    (new)=0.008223 secs   (old)=0.108704 secs
-------------------------------------------------------------------------------------
1000K    file_bytes_remove()   (new)=0.019177 secs   (old)=0.208722 secs
(~1M)    file_void_insert()    (new)=0.020519 secs   (old)=0.236202 secs
-------------------------------------------------------------------------------------
5000K    file_bytes_remove()   (new)=0.013800 secs   (old)=0.179805 secs
(~5M)    file_void_insert()    (new)=0.012629 secs   (old)=0.197460 secs
-------------------------------------------------------------------------------------
10000K   file_bytes_remove()   (new)=0.025863 secs   (old)=0.356722 secs
(~10M)   file_void_insert()    (new)=0.023418 secs   (old)=0.393732 secs
=====================================================================================


And here is my older code, for historical reasons, in case you're curious.
If you are new, here is the older version Im comparing speeds with.
Its much slower, and less elegant, but easier to understand.
But beware, the bigger the file your working with, the slower it gets.
Click to reveal..
Code:
#ifndef File_Open_RW_h
#define File_Open_RW_h
//
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//
//		File_Open_RW.h 
//		Library of 3DGS-like function filling some gaps in updating data MID-file
//		Equivalent to standard file_open_write() and file_open_append() functionality
//		but adds the EXTRA ability to insert STRING, VAR, or ASC data at mid-file positions
//
//		Author	:	EvilSOB
//		Written	: 	16-02-2009
//
//		Requirements:	None.
//
//		FUNCTIONS
//=======================================================================================
//		file_open_RW(STRING* name);
//---------------------------------------------------------------------------------------
//		Opens a file for reading and writing additional content at any point. 
//		If the file does not exist, it is created.
//		The function returns a file handle - that is a unique number to identify the file. 
//		The file handle is used by other functions to access that file. 
//---------------------------------------------------------------------------------------
//		Parameters:
//			name	- file name with or without path, STRING* or char*. 
//---------------------------------------------------------------------------------------
//		Returns:
//			File handle(type VAR), or 0 if the file could not be opened. 
//
//
//
//
//=======================================================================================
//		file_close_RW(var handle);
//---------------------------------------------------------------------------------------
//		Closes the file with the given handle. A file must be closed before other programs
//			can access it, or before it can be opened again in a different mode. As soon as
//			the file is closed, the handle becomes invalid.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle of the closing file.
//---------------------------------------------------------------------------------------
//		NOTE: 
//			Using lite-c file_close() on a file_open_RW() file works fine but wastes memory.
//
//
//
//
//=======================================================================================
//		file_str_insert(var handle, STRING* data, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes the given string into the file with the given handle. The file must be have
//			been opened with file_open_RW(). The string is unmodified, i.e. special 
//			sequences like '\n' are not converted. 
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			data		- Character string to be written into the file 
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//
//
//
//
//=======================================================================================
//		file_var_insert(var handle, var number, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes the given number or variable into the file with the given handle. The file
//			must have been opened with file_open_RW(). If the number has a decimal between
//			.001 and .999, the number is then written with 3 decimals, ending by a blank.
//			Otherwise the integer is written with no decimals, again ending by a blank.
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			number	- Value to be written into the file as a string 
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//
//
//
//
//=======================================================================================
//		file_asc_insert(var handle, var number, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Writes a single byte given by the number or variable (0..255) into the file with 
//		the given handle. The file must have been opened with file_open_RW(). 
//		After data-insertion, the read pointer is placed at the end of the inserted data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			number	- Number between 0 and 255.
//			offset	- Write position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//
//
//
//
//=======================================================================================
//		file_num_cut(var handle, var cut_qty, var offset, var mode)
//---------------------------------------------------------------------------------------
//		Removes cut_qty number of bytes from the the file with the given handle. The file 
//			must have been opened with file_open_RW(). 
//		After data-removal, the read pointer is placed at the position of the removed data.
//---------------------------------------------------------------------------------------
//		Parameters:
//			handle	- File handle 
//			cut_qtyr	- Quantity of bytes to be "cut" from the middle of the file.
//			offset	- Cut position in bytes from the position given by the mode parameter
//			mode		- 0 = from beginning of the file
//						  1 = from the current read position
//						  2 = from the end of the file. 
//---------------------------------------------------------------------------------------
//		Returns:
//			True	- file update was sucessful.
//			False	- file update failed. Due to invalid handle.
//			False	- file update failed. Due to file not opened with file_open_RW.
//
//
//
//
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//
//
#define Max_RW_files	10		//MAXIMUM file_insert files allowed open AT ANY ONE TIME
STRING*	RW_filename[Max_RW_files];
var 		RW_file[Max_RW_files];
//
function file_open_RW_startup()		//initialise empty File tracking table
{	var f; for(f=0; f<Max_RW_files; f++)	RW_filename[f] = RW_file[f] = NULL;	}
//
//
/////////////////////////////////////////////////////////////////////////////////////////
//
//
function file_open_RW(STRING* filename)		//open file for read/write capability
{	var f; for(f=0; f<Max_RW_files; f++)			//look for available slot
	{	if(RW_file[f]==NULL)									//in tracking table
		{	RW_filename[f] = str_create(_chr(filename));			//create entry 
			RW_file[f] 	 = file_open_read(filename);				//in vacant
			break;			}		}												//slot
	if(f==Max_RW_files)	return(NULL);	//no space in table to open new file
	return(RW_file[f]);			//return pointer to new insert-capable file
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_close_RW(var *file)			//close insert-capable entry in tracking table
{	if(*file==NULL)	return(false);	//not a valid file pointer
	var f; for(f=0; f<Max_RW_files; f++)	//look for table entry 
	{	if(RW_file[f]==*file)	break;		}		//that matches pointer
	if(f<Max_RW_files)			//clear table entry
	{	RW_file[f] = NULL;				//for re-use 
		str_remove(RW_filename[f]);	//and release memory 
		RW_filename[f] = NULL;			}	//used by string
	file_close(*file);		//close file whether it was in the table or not.
	return(true);
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_str_insert(var *file, char* text, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	var f; for(f=0; f<Max_RW_files; f++)		//look for table entry
	{	if(RW_file[f]==*file)	break;		}			//that matches pointer
	if(f==Max_RW_files)	return(false);	//not an insert-capable file
	if(mode == 3)
		offset += file_length(RW_file[f]);				//offset relates to end of file
	else if(mode == 1)
		offset += file_seek(RW_file[f], NULL, 4);		//offset relates to current position
	else	//mode==0
		offset += 0;											//offset relates to beginning of file
	int bytepos = offset;	//define position that changes take place at
	int remain  = file_length(RW_file[f]) - bytepos;	//and bytes-remaining in file
	int byt;	file_seek(RW_file[f],0,0);		//return read_position to start of file
	//Copy first half
	var*	PartA = (var*)malloc((int)sizeof(var)*bytepos);	//create read buffer PartA
	for(byt=0; byt<bytepos; byt++)	PartA[byt] = file_asc_read(RW_file[f]);	//and fill
	//Copy last half
	var*	PartB = (var*)malloc((int)sizeof(var)*remain);		//create read buffer PartA
	for(byt=0; byt<remain; byt++)		PartB[byt] = file_asc_read(RW_file[f]);	//and fill
	file_close(RW_file[f]);		//close the old file	
	file_delete(RW_filename[f]); 	//and delete it, so we can create a new one
	//Create replacement file
	RW_file[f] = file_open_write(RW_filename[f]);	//open new empty file
	for(byt=0; byt<bytepos; byt++)	file_asc_write(RW_file[f], PartA[byt]);	//start fill
	file_str_write(RW_file[f], text);		//write in the bit we've added
	bytepos = file_seek(RW_file[f], NULL, 4);	//calculate the read position to after data
	for(byt=0; byt<remain; byt++)	file_asc_write(RW_file[f], PartB[byt]);	//continue fill
	file_close(RW_file[f]);	//close newly created file
	RW_file[f] = file_open_read(RW_filename[f]);	//re-open it as insert-capable
	file_seek(RW_file[f], bytepos, 0);		//re-position read position to after added data
	*file = RW_file[f];		//reset pointer to file to calling function
	free(PartA);	free(PartB);	//free read buffer memory for first and second 'halves' of file
	return(true);	//return successful status	
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_asc_insert(var *file, var num, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	STRING* tmpStr = " ";		//temp space for to-be-written data
	str_for_asc(tmpStr, num);		//convert ASC value into CHAR character for writing
	var Result = file_str_insert(*file, tmpStr, offset, mode);	//write character 'string'
	str_remove(tmpStr);			//remove/free temp spaces from has-be-written data
	return(Result);		//inform caller of sucess/failure
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_var_insert(var *file, var num, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	STRING* tmpStr = ".............";		//temp space for to-be-written data
	str_for_num(tmpStr, num);		//convert number value into STRING for writing
	var Result = file_str_insert(*file, tmpStr, offset, mode);	//write character 'string'
	str_remove(tmpStr);			//remove/free temp spaces from has-be-written data
	return(Result);		//inform caller of sucess/failure
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
function file_num_cut(var *file, var cut_qty, var offset, var mode)
{	if(*file==NULL)	return(false);	//not a valid file pointer
	if(cut_qty==0)		return(true);	//NO characters needing extracting, assume OK
	var f; for(f=0; f<Max_RW_files; f++)		//look for table entry
	{	if(RW_file[f]==*file)	break;		}			//that matches pointer
	if(f==Max_RW_files)	return(false);	//not an insert-capable file
	if(mode == 3)
		offset += file_length(RW_file[f]);				//offset relates to end of file
	else if(mode == 1)
		offset += file_seek(RW_file[f], NULL, 4);		//offset relates to current position
	else	//mode==0
		offset += 0;											//offset relates to beginning of file
	int bytepos = offset;	//define position that changes take place at
	if(cut_qty<0)	bytepos -= abs(cut_qty);	//re-position read position to START of cut
	int remain  = file_length(RW_file[f]) - bytepos - cut_qty;	//calc bytes-remaining in file
	file_close(RW_file[f]);	//close source file
	file_rename(RW_filename[f], "temp.tmp");		//rename (to be deleted) source file
	var source = file_open_read("temp.tmp");	//open temp source file
	RW_file[f] = file_open_write(RW_filename[f]);	//open new empty file
	var byt; for(byt=0; byt<bytepos; byt++)	file_asc_write(RW_file[f], file_asc_read(source));
	for(byt=0; byt<abs(cut_qty); byt++)	file_asc_read(source);	//throw away junked data
	bytepos = file_seek(RW_file[f], NULL, 4);	//calculate the read position to after cut
	for(byt=0; byt<remain; byt++)	file_asc_write(RW_file[f], file_asc_read(source));
	file_close(source);	//close old source file
	file_delete("temp.tmp");	//delete old source file
	file_close(RW_file[f]);	//close newly created file
	RW_file[f] = file_open_read(RW_filename[f]);	//re-open it as insert-capable
	file_seek(RW_file[f], bytepos, 0);		//re-position read position to after added data
	*file = RW_file[f];		//reset pointer to file to calling function
	return(true);	//return successfule status	
}
//
//
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//
#endif	// File_Open_RW_h


Last edited by EvilSOB; 02/18/09 12:42. Reason: Updated / Overhauled
Re: Inserting data in the middle of a file [Re: EvilSOB] #251686
02/14/09 16:13
02/14/09 16:13
Joined: Aug 2008
Posts: 2,838
take me down to the paradise c...
Cowabanga Offline
Expert
Cowabanga  Offline
Expert

Joined: Aug 2008
Posts: 2,838
take me down to the paradise c...
Wow! Thanks EvilSOB!

Re: Inserting data in the middle of a file [Re: Cowabanga] #251703
02/14/09 16:51
02/14/09 16:51
Joined: Jan 2003
Posts: 4,615
Cambridge
Joey Offline
Expert
Joey  Offline
Expert

Joined: Jan 2003
Posts: 4,615
Cambridge
can you say something about performance compared to normal appending?

Re: Inserting data in the middle of a file [Re: Joey] #251753
02/14/09 18:23
02/14/09 18:23
Joined: Feb 2008
Posts: 3,232
Australia
EvilSOB Offline OP
Expert
EvilSOB  Offline OP
Expert

Joined: Feb 2008
Posts: 3,232
Australia
Errrr,....Ummmm,...., not really.
While testing this I found an intermittant bug that causes a application crash.
Only on files over 500k, but it may be cause Im using garbage data, but it still
needs fixing.
Work in progress with this, then I'll write a function to allow the removal of
X number of bytes from the middle of a file.

BUT, I can say for speed, mines bad cause its in code, but the append is handled
by the operating system. Mine takes about 3500 microseconds on a 10k file, and
append takes LESS than 1 microsecond !!!
So we cant really do ANY comparison between mine and appending.

Anyway, back to the de-bugging

[EDIT] De-bugging complete (till we find something else!?!). I found I was using
a var in my malloc calculations that fell over if one of the file 'halves' was larger than 260k.
The file_str_insert function is all that needs to be replaced, Ive edited my head post
with the corrected code.


Last edited by EvilSOB; 02/14/09 19:16. Reason: Bug Fix

"There is no fate but what WE make." - CEO Cyberdyne Systems Corp.
A8.30.5 Commercial
Re: Inserting data in the middle of a file [Re: EvilSOB] #251848
02/15/09 10:44
02/15/09 10:44
Joined: Feb 2008
Posts: 3,232
Australia
EvilSOB Offline OP
Expert
EvilSOB  Offline OP
Expert

Joined: Feb 2008
Posts: 3,232
Australia
Minor re-write has meant me replacing the entire top code-post.

Mostly re-naming of functions/variable to improve naming conventions.

Minor bug-fix for bug that fumbled things if more then one ReadWrite file was opened at any one time.

ADDED file_num_cut(HANDLE, NUM) function. Cuts out NUM number of characters from current read position.
If a negative NUM is supplied, characters are cut BACKWARDS fom the current read position instead.

Any suggestions for variants or new functions anyone?


"There is no fate but what WE make." - CEO Cyberdyne Systems Corp.
A8.30.5 Commercial
Re: Inserting data in the middle of a file [Re: EvilSOB] #252302
02/17/09 16:14
02/17/09 16:14
Joined: Jul 2004
Posts: 1,710
MMike Offline
Serious User
MMike  Offline
Serious User

Joined: Jul 2004
Posts: 1,710
Ok so when is this going to the wiki...?
And many thanks! This is very handy.


Last edited by MMike; 02/17/09 16:15.
Re: Inserting data in the middle of a file [Re: MMike] #252381
02/17/09 23:51
02/17/09 23:51
Joined: Jul 2008
Posts: 894
T
TechMuc Offline
User
TechMuc  Offline
User
T

Joined: Jul 2008
Posts: 894
thank you ofc, but just as a small side-note: The code will be as slow as hell with big files (as you use asc read with just one byte..).

Just test your code (i havn't - but had a short look at your code), with any big (+1MB) file.

You have to read all bytes until the write position at once.

Re: Inserting data in the middle of a file [Re: TechMuc] #252395
02/18/09 01:23
02/18/09 01:23
Joined: Feb 2008
Posts: 3,232
Australia
EvilSOB Offline OP
Expert
EvilSOB  Offline OP
Expert

Joined: Feb 2008
Posts: 3,232
Australia
I know, it was sluggish BIG TIME, but Im in the middle of testing a major overhaul that makes use
of the bulk reading capability of file_load().
I should be posting new code (but still with same function names and usage) in a couple of hours.


"There is no fate but what WE make." - CEO Cyberdyne Systems Corp.
A8.30.5 Commercial
Re: Inserting data in the middle of a file [Re: EvilSOB] #252468
02/18/09 12:43
02/18/09 12:43
Joined: Feb 2008
Posts: 3,232
Australia
EvilSOB Offline OP
Expert
EvilSOB  Offline OP
Expert

Joined: Feb 2008
Posts: 3,232
Australia
The NEW and IMPROVED version is now available in the top post,
along with performance specs.

Enjoy averyone...


"There is no fate but what WE make." - CEO Cyberdyne Systems Corp.
A8.30.5 Commercial
Re: Inserting data in the middle of a file [Re: EvilSOB] #252661
02/19/09 14:06
02/19/09 14:06
Joined: Jan 2003
Posts: 4,615
Cambridge
Joey Offline
Expert
Joey  Offline
Expert

Joined: Jan 2003
Posts: 4,615
Cambridge
you could use the older code for small files, since it's like five times faster than the new one. just a suggestion.

Page 1 of 2 1 2

Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1