1 //=============================================================================
2 //
3 //   File : KvsObject_file.cpp
4 //   Creation date : Fri Mar 18 21:30:48 CEST 2005
5 //   by Tonino Imbesi(Grifisx) and Alessandro Carbone(Noldor)
6 //
7 //   This file is part of the KVIrc IRC client distribution
8 //   Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
9 //
10 //   This program is FREE software. You can redistribute it and/or
11 //   modify it under the terms of the GNU General Public License
12 //   as published by the Free Software Foundation; either version 2
13 //   of the License, or (at your option) any later version.
14 //
15 //   This program is distributed in the HOPE that it will be USEFUL,
16 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 //   See the GNU General Public License for more details.
19 //
20 //   You should have received a copy of the GNU General Public License
21 //   along with this program. If not, write to the Free Software Foundation,
22 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=============================================================================
25 
26 #include "KvsObject_file.h"
27 #include "kvi_debug.h"
28 #include "KviLocale.h"
29 #include "KviError.h"
30 #include "KviFile.h"
31 #include "KviFileUtils.h"
32 #include "KvsObject_memoryBuffer.h"
33 
34 #include <QStringList>
35 //#include <QFile>
36 #include <QTextStream>
37 
38 #define CHECK_FILE_IS_OPEN                                       \
39 	if(!m_pFile->isOpen())                                       \
40 	{                                                            \
41 		c->warning(__tr2qs_ctx("File is not open!", "objects")); \
42 		return true;                                             \
43 	}
44 
45 // needed for $open()
46 
47 const char * const mod_tbl[] = {
48 	"Raw",
49 	"ReadOnly",
50 	"WriteOnly",
51 	"ReadWrite",
52 	"Append",
53 	"Truncate"
54 };
55 
56 const QIODevice::OpenMode mod_cod[] = {
57 	QIODevice::Unbuffered,
58 	QIODevice::ReadOnly,
59 	QIODevice::WriteOnly,
60 	QIODevice::ReadWrite,
61 	QIODevice::Append,
62 	QIODevice::Truncate
63 };
64 
65 #define mod_num (sizeof(mod_tbl) / sizeof(mod_tbl[0]))
66 
67 /*
68 	@doc:	file
69 	@keyterms:
70 		file object class, creating files
71 	@title:
72 		file class
73 	@type:
74 		class
75 	@short:
76 		I/O device that operates on files
77 	@inherits:
78 		[class]object[/class]
79 	@description:
80 		This object class provides access to files - basic I/O
81 		operations, copying, removing etc.
82 	@functions:
83 		!fn: $setName(<file_name:string>)
84 		Sets the file name to <file_name>. It does [b]not move[/b] the file,
85 		it just changes the file the object is [i]pointing to[/i]. You can
86 		not change names of already open files.[br]
87 		See also: [classfnc]$open[/classfnc](),
88 		[classfnc]$name[/classfnc]().
89 		!fn: <string> $name()
90 		Returns name set by [classfnc]$setName[/classfnc]().[br]
91 		See also: [classfnc]$setName[/classfnc]().
92 		!fn: $open(<mode1:string>, <mode2:string>)
93 		Attempts to open the file in specified mode or modes [i]sum[/i].
94 		Valid modes are:[br]
95 		[pre]
96 			RAW     - RAW, non-buffered access
97 			ReadOnly     - opens the file read-only
98 			WriteOnly    - opens the file write-only
99 			ReadWrite    - opens the file in read-write mode
100 			Append       - opens the file in append mode. The file index is set to the end of the file.
101 			Truncate     - truncates the file
102 		[/pre]
103 		If you call this function without any parameters, the file is
104 		opened in read-only mode.[br]
105 		When working with buffered files, data is not written directly
106 		to the file at once. You must call [classfnc]$flush[/classfnc]() to force it.[br]
107 		See also: [classfnc]$close[/classfnc](),
108 		[classfnc]$flush[/classfnc]().
109 		!fn: <boolean> $isOpen()
110 		Returns '1' if the file is open, '0' otherwise.
111 		!fn: $close()
112 		Closes the file, flushing the buffers first.[br]
113 		See also: [classfnc]$flush[/classfnc]().
114 		!fn: $flush()
115 		Flushes the file buffer to disk. Calling this after opening the
116 		file in RAW mode doesn't make much sense.[br]
117 		See also: [classfnc]$open[/classfnc](),
118 		[classfnc]$close[/classfnc]().
119 		!fn: <integer> $size()
120 		Returns current file size.
121 		!fn: <boolean> $atEnd()
122 		Returns '1' if you have reached end of the file, [b]0[/b] otherwise.
123 		[br]See also: [classfnc]$seek[/classfnc](),
124 		[classfnc]$where[/classfnc]().
125 		!fn: <integer> $where()
126 		Returns current position in the file (file index).[br]
127 		See also: [classfnc]$seek[/classfnc]().
128 		!fn: $seek(<index:integer>)
129 		Sets the file index to <index>.[br]
130 		See also: [classfnc]$where[/classfnc](),
131 		[classfnc]$atEnd[/classfnc]().
132 		!fn: $putch(<char>)
133 		Writes character <char> to the file and increments file
134 		index.[br]
135 		See also: [classfnc]$getch[/classfnc](),
136 		[classfnc]$ungetch[/classfnc]().
137 		!fn: <char> $getch()
138 		Reads a character from the file and increments file index.[br]
139 		See also: [classfnc]$putch[/classfnc](),
140 		[classfnc]$ungetch[/classfnc]().
141 		!fn: $ungetch(<char>)
142 		Puts the character <char> back to the file and
143 		decrements the file index. This is usually called to undo a
144 		$getch() call.[br]
145 		See also: [classfnc]$getch[/classfnc],
146 		[classfnc]$putch[/classfnc]().
147 		!fn: $readLine(<text_line:string>)
148 		Reads a line of text from the file and increments file index.
149 		!fn: $writeLine(<text_line:string>)
150 		Appends a line of text to the end of the file.
151 		$readBlock()
152 		$writeBlock()
153 */
154 
155 KVSO_BEGIN_REGISTERCLASS(KvsObject_file, "file", "object")
156 KVSO_REGISTER_HANDLER(KvsObject_file, "setName", setName)
157 KVSO_REGISTER_HANDLER(KvsObject_file, "name", name)
158 
159 KVSO_REGISTER_HANDLER(KvsObject_file, "open", open)
160 KVSO_REGISTER_HANDLER(KvsObject_file, "isOpen", isOpen)
161 KVSO_REGISTER_HANDLER(KvsObject_file, "close", close)
162 KVSO_REGISTER_HANDLER(KvsObject_file, "flush", flush)
163 
164 KVSO_REGISTER_HANDLER(KvsObject_file, "size", size)
165 KVSO_REGISTER_HANDLER(KvsObject_file, "resize", resize)
166 
167 KVSO_REGISTER_HANDLER(KvsObject_file, "atEnd", atEnd)
168 KVSO_REGISTER_HANDLER(KvsObject_file, "where", where)
169 KVSO_REGISTER_HANDLER(KvsObject_file, "seek", seek)
170 
171 KVSO_REGISTER_HANDLER(KvsObject_file, "putch", putch)
172 KVSO_REGISTER_HANDLER(KvsObject_file, "getch", getch)
173 KVSO_REGISTER_HANDLER(KvsObject_file, "ungetch", unGetch)
174 KVSO_REGISTER_HANDLER(KvsObject_file, "readByte", readByte)
175 
176 KVSO_REGISTER_HANDLER(KvsObject_file, "readBlock", readBlock)
177 KVSO_REGISTER_HANDLER(KvsObject_file, "writeBlock", writeBlock)
178 
179 KVSO_REGISTER_HANDLER(KvsObject_file, "readHexBlock", readHexBlock)
180 KVSO_REGISTER_HANDLER(KvsObject_file, "writeHexBlock", writeHexBlock)
181 
182 KVSO_REGISTER_HANDLER(KvsObject_file, "readLine", readLine)
183 KVSO_REGISTER_HANDLER(KvsObject_file, "writeLine", writeLine)
184 
185 KVSO_REGISTER_HANDLER(KvsObject_file, "write", write)
186 KVSO_REGISTER_HANDLER(KvsObject_file, "read", read)
187 
188 KVSO_END_REGISTERCLASS(KvsObject_file)
189 
190 KVSO_BEGIN_CONSTRUCTOR(KvsObject_file, KvsObject_widget)
191 m_pFile = new KviFile();
192 
193 KVSO_END_CONSTRUCTOR(KvsObject_file)
194 
195 KVSO_BEGIN_DESTRUCTOR(KvsObject_file)
196 
197 if(m_pFile)
198 	delete m_pFile;
199 
200 KVSO_END_CONSTRUCTOR(KvsObject_file)
201 
KVSO_CLASS_FUNCTION(file,setName)202 KVSO_CLASS_FUNCTION(file, setName)
203 {
204 	CHECK_INTERNAL_POINTER(m_pFile)
205 	QString szName;
206 	KVSO_PARAMETERS_BEGIN(c)
207 	KVSO_PARAMETER("file_name", KVS_PT_STRING, 0, szName)
208 	KVSO_PARAMETERS_END(c)
209 	m_pFile->setFileName(szName);
210 	return true;
211 }
212 
KVSO_CLASS_FUNCTION(file,name)213 KVSO_CLASS_FUNCTION(file, name)
214 {
215 	CHECK_INTERNAL_POINTER(m_pFile)
216 	c->returnValue()->setString(m_pFile->fileName());
217 	return true;
218 }
219 
KVSO_CLASS_FUNCTION(file,open)220 KVSO_CLASS_FUNCTION(file, open)
221 {
222 	CHECK_INTERNAL_POINTER(m_pFile)
223 	QStringList modes;
224 	KVSO_PARAMETERS_BEGIN(c)
225 	KVSO_PARAMETER("file_mode", KVS_PT_STRINGLIST, KVS_PF_OPTIONAL, modes)
226 	KVSO_PARAMETERS_END(c)
227 
228 	if(m_pFile->fileName().isEmpty())
229 	{
230 		c->warning(__tr2qs_ctx("Empty filename string", "objects"));
231 		return true;
232 	}
233 	QIODevice::OpenMode mod, sum;
234 	if(modes.empty())
235 		sum = QIODevice::ReadWrite | QIODevice::Append; // if no parameters given, default to ReadWrite | Append
236 	else
237 	{
238 		for(int idx = 0; idx < modes.count(); idx++)
239 		{
240 			int found = false;
241 			for(unsigned int j = 0; j < mod_num; j++)
242 			{
243 				if(KviQString::equalCI(modes.at(idx), mod_tbl[j]))
244 				{
245 					mod = mod_cod[j];
246 					found = true;
247 					break;
248 				}
249 			}
250 			if(found)
251 				sum = sum | mod;
252 			else
253 				c->warning(__tr2qs_ctx("No such open mode '%Q'", "objects"), &modes.at(idx));
254 		}
255 	}
256 	c->returnValue()->setBoolean(m_pFile->open(sum));
257 	return true;
258 }
259 
KVSO_CLASS_FUNCTION(file,isOpen)260 KVSO_CLASS_FUNCTION(file, isOpen)
261 {
262 	CHECK_INTERNAL_POINTER(m_pFile)
263 	c->returnValue()->setBoolean(m_pFile->isOpen());
264 	return true;
265 }
266 
KVSO_CLASS_FUNCTION(file,close)267 KVSO_CLASS_FUNCTION(file, close)
268 {
269 	CHECK_INTERNAL_POINTER(m_pFile)
270 	CHECK_FILE_IS_OPEN
271 	m_pFile->close();
272 	return true;
273 }
274 
KVSO_CLASS_FUNCTION(file,flush)275 KVSO_CLASS_FUNCTION(file, flush)
276 {
277 	CHECK_INTERNAL_POINTER(m_pFile)
278 	CHECK_FILE_IS_OPEN
279 	m_pFile->flush();
280 	return true;
281 }
282 
KVSO_CLASS_FUNCTION(file,size)283 KVSO_CLASS_FUNCTION(file, size)
284 {
285 	CHECK_INTERNAL_POINTER(m_pFile)
286 	c->returnValue()->setInteger((kvs_int_t)(m_pFile->size()));
287 	return true;
288 }
289 
KVSO_CLASS_FUNCTION(file,atEnd)290 KVSO_CLASS_FUNCTION(file, atEnd)
291 {
292 	CHECK_INTERNAL_POINTER(m_pFile)
293 	c->returnValue()->setInteger((kvs_int_t)(m_pFile->atEnd()));
294 	return true;
295 }
296 
KVSO_CLASS_FUNCTION(file,where)297 KVSO_CLASS_FUNCTION(file, where)
298 {
299 	CHECK_INTERNAL_POINTER(m_pFile)
300 	CHECK_FILE_IS_OPEN
301 	c->returnValue()->setInteger((kvs_int_t)(m_pFile->pos()));
302 	return true;
303 }
304 
KVSO_CLASS_FUNCTION(file,seek)305 KVSO_CLASS_FUNCTION(file, seek)
306 {
307 	CHECK_INTERNAL_POINTER(m_pFile)
308 	kvs_uint_t uIndex;
309 	KVSO_PARAMETERS_BEGIN(c)
310 	KVSO_PARAMETER("index", KVS_PT_UNSIGNEDINTEGER, 0, uIndex)
311 	KVSO_PARAMETERS_END(c)
312 	CHECK_FILE_IS_OPEN
313 	m_pFile->seek(uIndex);
314 	return true;
315 }
316 
KVSO_CLASS_FUNCTION(file,resize)317 KVSO_CLASS_FUNCTION(file, resize)
318 {
319 	CHECK_INTERNAL_POINTER(m_pFile)
320 	kvs_int_t iSize;
321 	KVSO_PARAMETERS_BEGIN(c)
322 	KVSO_PARAMETER("size", KVS_PT_INTEGER, 0, iSize)
323 	KVSO_PARAMETERS_END(c)
324 	CHECK_FILE_IS_OPEN
325 	m_pFile->resize(iSize);
326 	return true;
327 }
328 
KVSO_CLASS_FUNCTION(file,putch)329 KVSO_CLASS_FUNCTION(file, putch)
330 {
331 	CHECK_INTERNAL_POINTER(m_pFile)
332 	QString szChar;
333 	KVSO_PARAMETERS_BEGIN(c)
334 	KVSO_PARAMETER("char", KVS_PT_STRING, 0, szChar)
335 	KVSO_PARAMETERS_END(c)
336 	if(szChar.length() > 1)
337 		c->warning(__tr2qs_ctx("Argument too long, using only first char", "objects"));
338 	QByteArray szCh = szChar.toUtf8();
339 	if(!m_pFile->putChar(szCh[0]))
340 		c->warning(__tr2qs_ctx("Write error occurred!", "objects"));
341 	return true;
342 }
343 
KVSO_CLASS_FUNCTION(file,getch)344 KVSO_CLASS_FUNCTION(file, getch)
345 {
346 	CHECK_INTERNAL_POINTER(m_pFile)
347 	CHECK_FILE_IS_OPEN
348 	char ch;
349 	if(!m_pFile->getChar(&ch))
350 		c->warning(__tr2qs_ctx("Read error occurred!", "objects")); // c->error ?
351 	QString szChar = QChar(ch);
352 	c->returnValue()->setString(szChar);
353 	return true;
354 }
355 
KVSO_CLASS_FUNCTION(file,readByte)356 KVSO_CLASS_FUNCTION(file, readByte)
357 {
358 	CHECK_INTERNAL_POINTER(m_pFile)
359 	CHECK_FILE_IS_OPEN
360 	char ch;
361 	if(!m_pFile->getChar(&ch))
362 		c->warning(__tr2qs_ctx("Read error occurred!", "objects")); // c->error ?
363 
364 	c->returnValue()->setInteger((kvs_int_t)ch);
365 	return true;
366 }
367 
KVSO_CLASS_FUNCTION(file,unGetch)368 KVSO_CLASS_FUNCTION(file, unGetch)
369 {
370 	CHECK_INTERNAL_POINTER(m_pFile)
371 	CHECK_FILE_IS_OPEN
372 	QString szChar;
373 	KVSO_PARAMETERS_BEGIN(c)
374 	KVSO_PARAMETER("char", KVS_PT_STRING, 0, szChar)
375 	KVSO_PARAMETERS_END(c)
376 	if(szChar.length() > 1)
377 		c->warning(__tr2qs_ctx("Argument too long, using only the first char", "objects"));
378 	QByteArray szCh = szChar.toUtf8();
379 	m_pFile->ungetChar(szCh[0]);
380 	return true;
381 }
382 
KVSO_CLASS_FUNCTION(file,readBlock)383 KVSO_CLASS_FUNCTION(file, readBlock)
384 {
385 	CHECK_INTERNAL_POINTER(m_pFile)
386 	CHECK_FILE_IS_OPEN
387 	kvs_uint_t uLen;
388 	KviKvsObject * pObject;
389 	kvs_hobject_t hObject;
390 	KVSO_PARAMETERS_BEGIN(c)
391 	KVSO_PARAMETER("length", KVS_PT_UNSIGNEDINTEGER, 0, uLen)
392 	KVSO_PARAMETER("hobject", KVS_PT_HOBJECT, KVS_PF_OPTIONAL, hObject)
393 	KVSO_PARAMETERS_END(c)
394 	if(uLen > (kvs_uint_t)m_pFile->size())
395 		uLen = m_pFile->size();
396 	if(hObject)
397 	{
398 		pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject);
399 		if(!pObject)
400 		{
401 			c->warning(__tr2qs_ctx("Buffer parameter is not an object", "objects"));
402 			return true;
403 		}
404 		if(!pObject->inheritsClass("memorybuffer"))
405 		{
406 			c->warning(__tr2qs_ctx("Buffer parameter is not a memorybuffer object", "objects"));
407 			return true;
408 		}
409 
410 		((KvsObject_memoryBuffer *)pObject)->pBuffer()->append(m_pFile->read(uLen));
411 		return true;
412 	}
413 	else
414 	{
415 		char * buff = new char[uLen + 1];
416 
417 		int rlen = m_pFile->read(buff, uLen);
418 		buff[rlen] = '\0';
419 		QString szBlock(buff);
420 		delete[] buff;
421 		c->returnValue()->setString(szBlock);
422 	}
423 	return true;
424 }
425 
KVSO_CLASS_FUNCTION(file,read)426 KVSO_CLASS_FUNCTION(file, read)
427 {
428 	CHECK_INTERNAL_POINTER(m_pFile)
429 	CHECK_FILE_IS_OPEN
430 	QString szType;
431 	KVSO_PARAMETERS_BEGIN(c)
432 	KVSO_PARAMETER("type", KVS_PT_STRING, 0, szType)
433 	KVSO_PARAMETERS_END(c)
434 	if(KviQString::equalCI(szType, "String"))
435 	{
436 		QString szStr;
437 		m_pFile->load(szStr);
438 		c->returnValue()->setString(szStr);
439 	}
440 	else if(KviQString::equalCI(szType, "Integer"))
441 	{
442 		int iValue;
443 		m_pFile->load(iValue);
444 		c->returnValue()->setInteger(iValue);
445 	}
446 	else if(KviQString::equalCI(szType, "Array"))
447 	{
448 		QString szData;
449 		m_pFile->load(szData);
450 		KviKvsVariant * pVar = KviKvsVariant::unserialize(szData);
451 		if(pVar->isArray())
452 			c->returnValue()->setArray(pVar->array());
453 		else
454 			c->warning(__tr2qs_ctx("The incoming data is not an array", "objects"));
455 	}
456 	else if(KviQString::equalCI(szType, "Dict"))
457 	{
458 		QString szData;
459 		m_pFile->load(szData);
460 		KviKvsVariant * pVar = KviKvsVariant::unserialize(szData);
461 		if(pVar->isHash())
462 			c->returnValue()->setHash(pVar->hash());
463 		else
464 			c->warning(__tr2qs_ctx("The incoming data is not a dictionary", "objects"));
465 	}
466 	else if(KviQString::equalCI(szType, "String"))
467 	{
468 		QString szStr;
469 		m_pFile->load(szStr);
470 		c->returnValue()->setString(szStr);
471 	}
472 	else
473 	{
474 		c->warning(__tr2qs_ctx("Unsupported datatype '%Q'", "objects"), &szType);
475 	}
476 	return true;
477 }
478 
KVSO_CLASS_FUNCTION(file,write)479 KVSO_CLASS_FUNCTION(file, write)
480 {
481 	CHECK_INTERNAL_POINTER(m_pFile)
482 	CHECK_FILE_IS_OPEN
483 	KviKvsVariant * pVariantData;
484 	KVSO_PARAMETERS_BEGIN(c)
485 	KVSO_PARAMETER("variant_data", KVS_PT_VARIANT, 0, pVariantData)
486 	KVSO_PARAMETERS_END(c)
487 	if(pVariantData->isInteger())
488 	{
489 		kvs_int_t num;
490 		pVariantData->asInteger(num);
491 		m_pFile->save(num);
492 	}
493 	if(pVariantData->isHash() || pVariantData->isArray() || pVariantData->isString())
494 	{
495 		QString szTmp;
496 		pVariantData->serialize(szTmp);
497 		m_pFile->save(szTmp);
498 	}
499 	return true;
500 }
501 
KVSO_CLASS_FUNCTION(file,writeBlock)502 KVSO_CLASS_FUNCTION(file, writeBlock)
503 {
504 	CHECK_INTERNAL_POINTER(m_pFile)
505 	kvs_uint_t uLen;
506 	KviKvsObject * pObject;
507 	KviKvsVariant * pVariantData;
508 	kvs_hobject_t hObject;
509 	KVSO_PARAMETERS_BEGIN(c)
510 	KVSO_PARAMETER("string_or_hobject", KVS_PT_VARIANT, 0, pVariantData)
511 	KVSO_PARAMETER("length", KVS_PT_UNSIGNEDINTEGER, KVS_PF_OPTIONAL, uLen)
512 	KVSO_PARAMETERS_END(c)
513 	if(!m_pFile->isOpen())
514 		c->warning(__tr2qs_ctx("File is not open!", "objects"));
515 	else
516 	{
517 		if(pVariantData->isHObject())
518 		{
519 			pVariantData->asHObject(hObject);
520 			pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject);
521 			if(!pObject)
522 			{
523 				c->warning(__tr2qs_ctx("Buffer parameter is not an object", "objects"));
524 				return true;
525 			}
526 			if(pObject->inheritsClass("memorybuffer"))
527 			{
528 				if(!uLen)
529 				{
530 					if(((KvsObject_memoryBuffer *)pObject)->pBuffer()->size())
531 						uLen = ((KvsObject_memoryBuffer *)pObject)->pBuffer()->size();
532 					else
533 					{
534 						c->warning(__tr2qs_ctx("The memoryBuffer object is empty: nothing will be saved", "objects"));
535 					}
536 				}
537 				const char * pData = ((KvsObject_memoryBuffer *)pObject)->pBuffer()->data();
538 				int rlen = m_pFile->write(pData, uLen);
539 				c->returnValue()->setInteger(rlen);
540 
541 			}
542 			else
543 			{
544 				c->warning(__tr2qs_ctx("Buffer parameter is not a memorybuffer object", "objects"));
545 				return true;
546 			}
547 		}
548 		else
549 		{
550 			if(!pVariantData->isString())
551 			{
552 				c->warning(__tr2qs_ctx("Block parameter must be a string or a memorybuffer object", "objects"));
553 				return true;
554 			}
555 			QString szBlock;
556 			pVariantData->asString(szBlock);
557 			QByteArray block = szBlock.toUtf8();
558 			int rlen = m_pFile->write(block.data(), uLen);
559 			c->returnValue()->setInteger(rlen);
560 		}
561 	}
562 	return true;
563 }
564 
KVSO_CLASS_FUNCTION(file,readLine)565 KVSO_CLASS_FUNCTION(file, readLine)
566 {
567 	CHECK_INTERNAL_POINTER(m_pFile)
568 	CHECK_FILE_IS_OPEN
569 	QString buffer;
570 
571 	buffer = m_pFile->readLine();
572 	c->returnValue()->setString(buffer);
573 	return true;
574 }
575 
KVSO_CLASS_FUNCTION(file,writeLine)576 KVSO_CLASS_FUNCTION(file, writeLine)
577 {
578 	CHECK_INTERNAL_POINTER(m_pFile)
579 	CHECK_FILE_IS_OPEN
580 	QString szLine;
581 	KVSO_PARAMETERS_BEGIN(c)
582 	KVSO_PARAMETER("text_line", KVS_PT_STRING, 0, szLine)
583 	KVSO_PARAMETERS_END(c)
584 	QTextStream ts(m_pFile);
585 	ts << szLine;
586 	return true;
587 }
588 
KVSO_CLASS_FUNCTION(file,readHexBlock)589 KVSO_CLASS_FUNCTION(file, readHexBlock)
590 {
591 	CHECK_INTERNAL_POINTER(m_pFile)
592 	CHECK_FILE_IS_OPEN
593 	kvs_uint_t uLen;
594 	KVSO_PARAMETERS_BEGIN(c)
595 	KVSO_PARAMETER("length", KVS_PT_UNSIGNEDINTEGER, 0, uLen)
596 	KVSO_PARAMETERS_END(c)
597 	if(uLen > (kvs_uint_t)m_pFile->size())
598 		uLen = m_pFile->size();
599 	char * buff = new char[uLen];
600 	char * str = new char[(uLen * 2) + 1];
601 	m_pFile->flush(); // advice from QFile man page (to avoid trash)
602 	int rlen = m_pFile->read(buff, uLen);
603 	int index = 0;
604 	unsigned char byte, msb, lsb = 0;
605 	for(int i = 0; i < rlen; i++)
606 	{
607 		byte = (unsigned char)buff[i];
608 		lsb = byte & 0x0f;
609 		msb = byte >> 4;
610 		msb > 9 ? msb += '7' : msb += '0';
611 		lsb > 9 ? lsb += '7' : lsb += '0';
612 		str[index++] = msb;
613 		str[index++] = lsb;
614 	}
615 	str[index] = '\0';
616 	c->returnValue()->setString(str);
617 	delete[] str;
618 	delete[] buff;
619 	return true;
620 }
621 
KVSO_CLASS_FUNCTION(file,writeHexBlock)622 KVSO_CLASS_FUNCTION(file, writeHexBlock)
623 {
624 	CHECK_INTERNAL_POINTER(m_pFile)
625 	CHECK_FILE_IS_OPEN
626 	QString szBlock;
627 	kvs_uint_t uLen;
628 	KVSO_PARAMETERS_BEGIN(c)
629 	KVSO_PARAMETER("text_block", KVS_PT_STRING, 0, szBlock)
630 	KVSO_PARAMETER("length", KVS_PT_UNSIGNEDINTEGER, KVS_PF_OPTIONAL, uLen)
631 	KVSO_PARAMETERS_END(c)
632 	if(szBlock.length() % 2)
633 	{
634 		c->warning(__tr2qs_ctx("Length of hex string is not multiple of 2", "objects"));
635 		return true;
636 	}
637 	if(uLen > ((uint)szBlock.length() / 2) || !uLen)
638 		uLen = szBlock.length();
639 	else
640 		uLen *= 2;
641 	unsigned char byte, lsb, msb;
642 	for(unsigned int i = 0; i < uLen; i += 2)
643 	{
644 		msb = szBlock.at(i).toLatin1();
645 		lsb = szBlock.at(i + 1).toLatin1();
646 
647 		if(((msb >= 'A' && msb <= 'F') || (msb >= '0' && msb <= '9')) && ((lsb >= 'A' && lsb <= 'F') || (lsb >= '0' && lsb <= '9')))
648 		{
649 			msb >= 'A' ? msb -= '7' : msb -= '0';
650 			lsb >= 'A' ? lsb -= '7' : lsb -= '0';
651 		}
652 		else
653 		{
654 			c->warning(__tr2qs_ctx("The hex string is not correct!", "objects"));
655 			return true;
656 		}
657 		byte = (msb * 16) + lsb;
658 		m_pFile->putChar(byte);
659 	}
660 	c->returnValue()->setInteger(uLen / 2);
661 	return true;
662 }
663