1// Sun, 18 Jun 2000
2// Y.Takagi
3
4#if defined(__HAIKU__) || defined(HAIKU_TARGET_PLATFORM_BONE)
5#	include <sys/socket.h>
6#	include <netinet/in.h>
7#else
8#	include <net/socket.h>
9#endif
10
11#include <fstream>
12#include <list>
13#include <cstring>
14
15#include "IppContent.h"
16
17/*----------------------------------------------------------------------*/
18
19short readLength(istream &is)
20{
21	short len = 0;
22	is.read((char *)&len, sizeof(short));
23	len = ntohs(len);
24	return len;
25}
26
27void writeLength(ostream &os, short len)
28{
29	len = htons(len);
30	os.write((char *)&len, sizeof(short));
31}
32
33/*----------------------------------------------------------------------*/
34
35DATETIME::DATETIME()
36{
37	memset(this, 0, sizeof(DATETIME));
38}
39
40DATETIME::DATETIME(const DATETIME &dt)
41{
42	memcpy(this, &dt.datetime, sizeof(DATETIME));
43}
44
45DATETIME & DATETIME::operator = (const DATETIME &dt)
46{
47	memcpy(this, &dt.datetime, sizeof(DATETIME));
48	return *this;
49}
50
51istream& operator >> (istream &is, DATETIME &attr)
52{
53	return is;
54}
55
56ostream& operator << (ostream &os, const DATETIME &attr)
57{
58	return os;
59}
60
61
62/*----------------------------------------------------------------------*/
63
64IppAttribute::IppAttribute(IPP_TAG t)
65	: tag(t)
66{
67}
68
69int IppAttribute::length() const
70{
71	return 1;
72}
73
74istream &IppAttribute::input(istream &is)
75{
76	return is;
77}
78
79ostream &IppAttribute::output(ostream &os) const
80{
81	os << (unsigned char)tag;
82	return os;
83}
84
85ostream &IppAttribute::print(ostream &os) const
86{
87	os << "Tag: " << hex << (int)tag << '\n';
88	return os;
89}
90
91/*----------------------------------------------------------------------*/
92
93IppNamedAttribute::IppNamedAttribute(IPP_TAG t)
94	: IppAttribute(t)
95{
96}
97
98IppNamedAttribute::IppNamedAttribute(IPP_TAG t, const char *s)
99	: IppAttribute(t), name(s ? s : "")
100{
101}
102
103int IppNamedAttribute::length() const
104{
105	return IppAttribute::length() + 2 + name.length();
106}
107
108istream &IppNamedAttribute::input(istream &is)
109{
110	short len = readLength(is);
111
112	if (0 < len) {
113		char *buffer = new char[len + 1];
114		is.read(buffer, len);
115		buffer[len] = '\0';
116		name = buffer;
117		delete [] buffer;
118	}
119
120	return is;
121}
122
123ostream &IppNamedAttribute::output(ostream &os) const
124{
125	IppAttribute::output(os);
126
127	writeLength(os, name.length());
128	os << name;
129
130	return os;
131}
132
133ostream &IppNamedAttribute::print(ostream &os) const
134{
135	IppAttribute::print(os);
136	os << '\t' << "Name: " << name << '\n';
137	return os;
138}
139
140/*----------------------------------------------------------------------*/
141
142IppNoValueAttribute::IppNoValueAttribute(IPP_TAG t)
143	: IppNamedAttribute(t)
144{
145}
146
147IppNoValueAttribute::IppNoValueAttribute(IPP_TAG t, const char *n)
148	: IppNamedAttribute(t, n)
149{
150}
151
152int IppNoValueAttribute::length() const
153{
154	return IppAttribute::length() + 2;
155}
156
157istream &IppNoValueAttribute::input(istream &is)
158{
159	IppNamedAttribute::input(is);
160
161	short len = readLength(is);
162
163	if (0 < len) {
164		is.seekg(len, ios::cur);
165	}
166
167	return is;
168}
169
170ostream &IppNoValueAttribute::output(ostream &os) const
171{
172	IppAttribute::output(os);
173
174	writeLength(os, 0);
175
176	return os;
177}
178
179ostream &IppNoValueAttribute::print(ostream &os) const
180{
181	return IppNamedAttribute::print(os);
182}
183
184/*----------------------------------------------------------------------*/
185
186IppIntegerAttribute::IppIntegerAttribute(IPP_TAG t)
187	: IppNamedAttribute(t), value(0)
188{
189}
190
191IppIntegerAttribute::IppIntegerAttribute(IPP_TAG t, const char *n, int v)
192	: IppNamedAttribute(t, n), value(v)
193{
194}
195
196int IppIntegerAttribute::length() const
197{
198	return IppNamedAttribute::length() + 2 + 4;
199}
200
201istream &IppIntegerAttribute::input(istream &is)
202{
203	IppNamedAttribute::input(is);
204
205	short len = readLength(is);
206
207	if (0 < len && len <= 4) {
208		is.read((char *)&value, sizeof(value));
209		value = ntohl(value);
210	} else {
211		is.seekg(len, ios::cur);
212	}
213
214	return is;
215}
216
217ostream &IppIntegerAttribute::output(ostream &os) const
218{
219	IppNamedAttribute::output(os);
220
221	writeLength(os, 4);
222	unsigned long val = htonl(value);
223	os.write((char *)&val, sizeof(val));
224	return os;
225}
226
227ostream &IppIntegerAttribute::print(ostream &os) const
228{
229	IppNamedAttribute::print(os);
230	os << '\t' << "Value: " << dec << value << '\n';
231	return os;
232}
233
234/*----------------------------------------------------------------------*/
235
236IppBooleanAttribute::IppBooleanAttribute(IPP_TAG t)
237	: IppNamedAttribute(t), value(false)
238{
239}
240
241IppBooleanAttribute::IppBooleanAttribute(IPP_TAG t, const char *n, bool f)
242	: IppNamedAttribute(t, n), value(f)
243{
244}
245
246int IppBooleanAttribute::length() const
247{
248	return IppNamedAttribute::length() + 2 + 1;
249}
250
251
252istream &IppBooleanAttribute::input(istream &is)
253{
254	IppNamedAttribute::input(is);
255
256	short len = readLength(is);
257
258	if (0 < len && len <= 1) {
259		char c;
260		is.read((char *)&c, sizeof(c));
261		value = c ? true : false;
262	} else {
263		is.seekg(len, ios::cur);
264	}
265
266	return is;
267}
268
269ostream &IppBooleanAttribute::output(ostream &os) const
270{
271	IppNamedAttribute::output(os);
272
273	writeLength(os, 1);
274	char c = (char)value;
275	os.write((char *)&c, sizeof(c));
276
277	return os;
278}
279
280ostream &IppBooleanAttribute::print(ostream &os) const
281{
282	IppNamedAttribute::print(os);
283	os << '\t' << "Value: " << value << '\n';
284	return os;
285}
286
287/*----------------------------------------------------------------------*/
288
289IppDatetimeAttribute::IppDatetimeAttribute(IPP_TAG t)
290	: IppNamedAttribute(t)
291{
292}
293
294IppDatetimeAttribute::IppDatetimeAttribute(IPP_TAG t, const char *n, const DATETIME *dt)
295	: IppNamedAttribute(t, n), datetime(*dt)
296{
297}
298
299int IppDatetimeAttribute::length() const
300{
301	return IppNamedAttribute::length() + 2 + 11;
302}
303
304istream &IppDatetimeAttribute::input(istream &is)
305{
306	IppNamedAttribute::input(is);
307
308	short len = readLength(is);
309
310	if (0 < len) {
311		if (len == 11) {
312			is >> datetime;
313		} else {
314			is.seekg(len, ios::cur);
315		}
316	}
317
318	return is;
319}
320
321ostream &IppDatetimeAttribute::output(ostream &os) const
322{
323	IppNamedAttribute::output(os);
324
325	writeLength(os, 11);
326	os << datetime;
327
328	return os;
329}
330
331ostream &IppDatetimeAttribute::print(ostream &os) const
332{
333	IppNamedAttribute::print(os);
334	os << '\t' << "Value(DateTime): " << datetime << '\n';
335	return os;
336}
337
338/*----------------------------------------------------------------------*/
339
340IppStringAttribute::IppStringAttribute(IPP_TAG t)
341	: IppNamedAttribute(t)
342{
343}
344
345IppStringAttribute::IppStringAttribute(IPP_TAG t, const char *n, const char *s)
346: IppNamedAttribute(t, n), text(s ? s : "")
347{
348}
349
350int IppStringAttribute::length() const
351{
352	return IppNamedAttribute::length() + 2 + text.length();
353}
354
355istream &IppStringAttribute::input(istream &is)
356{
357	IppNamedAttribute::input(is);
358
359	short len = readLength(is);
360
361	if (0 < len) {
362		char *buffer = new char[len + 1];
363		is.read(buffer, len);
364		buffer[len] = '\0';
365		text = buffer;
366		delete [] buffer;
367	}
368
369	return is;
370}
371
372ostream &IppStringAttribute::output(ostream &os) const
373{
374	IppNamedAttribute::output(os);
375
376	writeLength(os, text.length());
377	os << text;
378
379	return os;
380}
381
382ostream &IppStringAttribute::print(ostream &os) const
383{
384	IppNamedAttribute::print(os);
385	os << '\t' << "Value: " << text << '\n';
386	return os;
387}
388
389/*----------------------------------------------------------------------*/
390
391IppDoubleStringAttribute::IppDoubleStringAttribute(IPP_TAG t)
392	: IppNamedAttribute(t)
393{
394}
395
396IppDoubleStringAttribute::IppDoubleStringAttribute(IPP_TAG t, const char *n, const char *s1, const char *s2)
397: IppNamedAttribute(t, n), text1(s1 ? s1 : ""), text2(s2 ? s2 : "")
398{
399}
400
401int IppDoubleStringAttribute::length() const
402{
403	return IppNamedAttribute::length() + 2 + text1.length() + 2  + text2.length();
404}
405
406istream &IppDoubleStringAttribute::input(istream &is)
407{
408	IppNamedAttribute::input(is);
409
410	short len = readLength(is);
411
412	if (0 < len) {
413		char *buffer = new char[len + 1];
414		is.read(buffer, len);
415		buffer[len] = '\0';
416		text1 = buffer;
417		delete [] buffer;
418	}
419
420	len = readLength(is);
421
422	if (0 < len) {
423		char *buffer = new char[len + 1];
424		is.read(buffer, len);
425		buffer[len] = '\0';
426		text2 = buffer;
427		delete [] buffer;
428	}
429
430	return is;
431}
432
433ostream &IppDoubleStringAttribute::output(ostream &os) const
434{
435	IppNamedAttribute::output(os);
436
437	writeLength(os, text1.length());
438	os << text1;
439
440	writeLength(os, text2.length());
441	os << text2;
442
443	return os;
444}
445
446ostream &IppDoubleStringAttribute::print(ostream &os) const
447{
448	IppNamedAttribute::print(os);
449	os << '\t' << "Value1: " << text1 << '\n';
450	os << '\t' << "Value2: " << text2 << '\n';
451	return os;
452}
453
454/*----------------------------------------------------------------------*/
455
456IppResolutionAttribute::IppResolutionAttribute(IPP_TAG t)
457	: IppNamedAttribute(t), xres(0), yres(0), resolution_units((IPP_RESOLUTION_UNITS)0)
458{
459}
460
461IppResolutionAttribute::IppResolutionAttribute(IPP_TAG t, const char *n, int x, int y, IPP_RESOLUTION_UNITS u)
462	: IppNamedAttribute(t, n), xres(x), yres(y), resolution_units(u)
463{
464}
465
466int IppResolutionAttribute::length() const
467{
468	return IppNamedAttribute::length() + 2 + 4 + 2 + 4 + 2 + 1;
469}
470
471istream &IppResolutionAttribute::input(istream &is)
472{
473	IppNamedAttribute::input(is);
474
475	short len = readLength(is);
476
477	if (0 < len && len <= 4) {
478		is.read((char *)&xres, sizeof(xres));
479		xres = ntohl(xres);
480	} else {
481		is.seekg(len, ios::cur);
482	}
483
484	len = readLength(is);
485
486	if (0 < len && len <= 4) {
487		is.read((char *)&yres, sizeof(yres));
488		yres = ntohl(yres);
489	} else {
490		is.seekg(len, ios::cur);
491	}
492
493	len = readLength(is);
494
495	if (len == 1) {
496		char c;
497		is.read((char *)&c, sizeof(c));
498		resolution_units = (IPP_RESOLUTION_UNITS)c;
499	} else {
500		is.seekg(len, ios::cur);
501	}
502
503	return is;
504}
505
506ostream &IppResolutionAttribute::output(ostream &os) const
507{
508	IppNamedAttribute::output(os);
509
510	writeLength(os, 4);
511	unsigned long val = htonl(xres);
512	os.write((char *)&val, sizeof(val));
513
514	writeLength(os, 4);
515	val = htonl(yres);
516	os.write((char *)&val, sizeof(val));
517
518	writeLength(os, 1);
519	unsigned char c = (unsigned char)resolution_units;
520	os.write((char *)&c, sizeof(c));
521
522	return os;
523}
524
525ostream &IppResolutionAttribute::print(ostream &os) const
526{
527	IppNamedAttribute::print(os);
528	os << '\t' << "Value(xres): " << dec << xres << '\n';
529	os << '\t' << "Value(yres): " << dec << yres << '\n';
530	os << '\t' << "Value(unit): " << dec << resolution_units << '\n';
531	return os;
532}
533
534/*----------------------------------------------------------------------*/
535
536IppRangeOfIntegerAttribute::IppRangeOfIntegerAttribute(IPP_TAG t)
537	: IppNamedAttribute(t), lower(0), upper(0)
538{
539}
540
541IppRangeOfIntegerAttribute::IppRangeOfIntegerAttribute(IPP_TAG t, const char *n, int l, int u)
542	: IppNamedAttribute(t, n), lower(l), upper(u)
543{
544}
545
546int IppRangeOfIntegerAttribute::length() const
547{
548	return IppNamedAttribute::length() + 2 + 4 + 2 + 4;
549}
550
551istream &IppRangeOfIntegerAttribute::input(istream &is)
552{
553	IppNamedAttribute::input(is);
554
555	short len = readLength(is);
556
557	if (0 < len && len <= 4) {
558		is.read((char *)&lower, sizeof(lower));
559		lower = ntohl(lower);
560	} else {
561		is.seekg(len, ios::cur);
562	}
563
564	len = readLength(is);
565
566	if (0 < len && len <= 4) {
567		is.read((char *)&upper, sizeof(upper));
568		upper = ntohl(upper);
569	} else {
570		is.seekg(len, ios::cur);
571	}
572
573	return is;
574}
575
576ostream &IppRangeOfIntegerAttribute::output(ostream &os) const
577{
578	IppNamedAttribute::output(os);
579
580	writeLength(os, 4);
581	unsigned long val = htonl(lower);
582	os.write((char *)&val, sizeof(val));
583
584	writeLength(os, 4);
585	val = htonl(upper);
586	os.write((char *)&val, sizeof(val));
587
588	return os;
589}
590
591ostream &IppRangeOfIntegerAttribute::print(ostream &os) const
592{
593	IppNamedAttribute::print(os);
594	os << '\t' << "Value(lower): " << dec << lower << '\n';
595	os << '\t' << "Value(upper): " << dec << upper << '\n';
596	return os;
597}
598
599/*----------------------------------------------------------------------*/
600
601IppContent::IppContent()
602{
603	version      = 0x0100;
604	operation_id = IPP_GET_PRINTER_ATTRIBUTES;
605	request_id   = 0x00000001;
606
607	is = NULL;
608	size = -1;
609}
610
611IppContent::~IppContent()
612{
613	for (list<IppAttribute *>::const_iterator it = attrs.begin(); it != attrs.end(); it++) {
614		delete (*it);
615	}
616}
617
618unsigned short IppContent::getVersion() const
619{
620	return version;
621}
622
623void IppContent::setVersion(unsigned short i)
624{
625	version = i;
626}
627
628
629IPP_OPERATION_ID IppContent::getOperationId() const
630{
631	return (IPP_OPERATION_ID)operation_id;
632}
633
634void IppContent::setOperationId(IPP_OPERATION_ID i)
635{
636	operation_id = i;
637}
638
639IPP_STATUS_CODE IppContent::getStatusCode() const
640{
641	return (IPP_STATUS_CODE)operation_id;
642}
643
644unsigned long IppContent::getRequestId() const
645{
646	return request_id;
647}
648
649void IppContent::setRequestId(unsigned long i)
650{
651	request_id = i;
652}
653
654istream &IppContent::input(istream &is)
655{
656	if (!is.read((char *)&version, sizeof(version))) {
657		return is;
658	}
659
660	version = ntohs(version);
661
662	if (!is.read((char *)&operation_id, sizeof(operation_id))) {
663		return is;
664	}
665
666	operation_id = ntohs(operation_id);
667
668	if (!is.read((char *)&request_id, sizeof(request_id))) {
669		return is;
670	}
671
672	request_id = ntohl(request_id);
673	char tag;
674
675	while (1) {
676
677		if (!is.read((char *)&tag, sizeof(tag))) {
678			return is;
679		}
680
681		if (tag <= 0x0F) {	// delimiter
682
683//			case IPP_OPERATION_ATTRIBUTES_TAG:
684//			case IPP_JOB_ATTRIBUTES_TAG:
685//			case IPP_END_OF_ATTRIBUTES_TAG:
686//			case IPP_PRINTER_ATTRIBUTES_TAG:
687//			case IPP_UNSUPPORTED_ATTRIBUTES_TAG:
688
689			attrs.push_back(new IppAttribute((IPP_TAG)tag));
690			if (tag == IPP_END_OF_ATTRIBUTES_TAG) {
691				break;
692			}
693
694		} else if (tag <= 0x1F) {
695
696			IppNoValueAttribute *attr = new IppNoValueAttribute((IPP_TAG)tag);
697			is >> *attr;
698			attrs.push_back(attr);
699
700		} else if (tag <= 0x2F) {	// integer values
701
702			switch (tag) {
703			case IPP_INTEGER:
704			case IPP_ENUM:
705				{
706					IppIntegerAttribute *attr = new IppIntegerAttribute((IPP_TAG)tag);
707					is >> *attr;
708					attrs.push_back(attr);
709				}
710				break;
711			case IPP_BOOLEAN:
712				{
713					IppBooleanAttribute *attr = new IppBooleanAttribute((IPP_TAG)tag);
714					is >> *attr;
715					attrs.push_back(attr);
716				}
717				break;
718			default:
719				{
720					short len = readLength(is);
721					is.seekg(len, ios::cur);
722					len = readLength(is);
723					is.seekg(len, ios::cur);
724				}
725				break;
726			}
727
728		} else if (tag <= 0x3F) {	// octetString values
729
730			switch (tag) {
731			case IPP_STRING:
732				{
733					IppStringAttribute *attr = new IppStringAttribute((IPP_TAG)tag);
734					is >> *attr;
735					attrs.push_back(attr);
736				}
737				break;
738			case IPP_DATETIME:
739				{
740					IppDatetimeAttribute *attr = new IppDatetimeAttribute((IPP_TAG)tag);
741					is >> *attr;
742					attrs.push_back(attr);
743				}
744				break;
745			case IPP_RESOLUTION:
746				{
747					IppResolutionAttribute *attr = new IppResolutionAttribute((IPP_TAG)tag);
748					is >> *attr;
749					attrs.push_back(attr);
750				}
751				break;
752			case IPP_RANGE_OF_INTEGER:
753				{
754					IppRangeOfIntegerAttribute *attr = new IppRangeOfIntegerAttribute((IPP_TAG)tag);
755					is >> *attr;
756					attrs.push_back(attr);
757				}
758				break;
759			case IPP_TEXT_WITH_LANGUAGE:
760			case IPP_NAME_WITH_LANGUAGE:
761				{
762					IppDoubleStringAttribute *attr = new IppDoubleStringAttribute((IPP_TAG)tag);
763					is >> *attr;
764					attrs.push_back(attr);
765				}
766				break;
767			default:
768				{
769					short len = readLength(is);
770					is.seekg(len, ios::cur);
771					len = readLength(is);
772					is.seekg(len, ios::cur);
773				}
774				break;
775			}
776
777		} else if (tag <= 0x5F) {	// character-string values
778
779//			case IPP_TEXT_WITHOUT_LANGUAGE:
780//			case IPP_NAME_WITHOUT_LANGUAGE:
781//			case IPP_KEYWORD:
782//			case IPP_URI:
783//			case IPP_URISCHEME:
784//			case IPP_CHARSET:
785//			case IPP_NATURAL_LANGUAGE:
786//			case IPP_MIME_MEDIA_TYPE:
787
788			IppStringAttribute *attr = new IppStringAttribute((IPP_TAG)tag);
789			is >> *attr;
790			attrs.push_back(attr);
791		}
792	}
793	return is;
794}
795
796ostream &IppContent::output(ostream &os) const
797{
798	unsigned short ns_version = htons(version);						// version-number
799	os.write((char *)&ns_version, sizeof(ns_version));				// version-number
800
801	unsigned short ns_operation_id = htons(operation_id);			// operation-id
802	os.write((char *)&ns_operation_id, sizeof(ns_operation_id));	// operation-id
803
804	unsigned long ns_request_id = htonl(request_id);				// request-id
805	os.write((char *)&ns_request_id, sizeof(ns_request_id));		// request-id
806
807	for (list<IppAttribute *>::const_iterator it = attrs.begin(); it != attrs.end(); it++) {
808		os << *(*it);
809	}
810
811	ifstream ifs;
812	istream *iss = is;
813	if (iss == NULL) {
814		if (!file_path.empty()) {
815			ifs.open(file_path.c_str(), ios::in | ios::binary);
816			iss = &ifs;
817		}
818	}
819	if (iss && iss->good()) {
820		if (iss->good()) {
821			char c;
822			while (iss->get(c)) {
823				os.put(c);
824			}
825		}
826	}
827
828	return os;
829}
830
831void IppContent::setDelimiter(IPP_TAG tag)
832{
833	attrs.push_back(new IppAttribute(tag));
834}
835
836void IppContent::setInteger(const char *name, int value)
837{
838	attrs.push_back(new IppIntegerAttribute(IPP_INTEGER, name, value));
839}
840
841void IppContent::setBoolean(const char *name, bool value)
842{
843	attrs.push_back(new IppBooleanAttribute(IPP_BOOLEAN, name, value));
844}
845
846void IppContent::setString(const char *name, const char *value)
847{
848	attrs.push_back(new IppStringAttribute(IPP_STRING, name, value));
849}
850
851void IppContent::setDateTime(const char *name, const DATETIME *dt)
852{
853	attrs.push_back(new IppDatetimeAttribute(IPP_DATETIME, name, dt));
854}
855
856void IppContent::setResolution(const char *name, int x, int y, IPP_RESOLUTION_UNITS u)
857{
858	attrs.push_back(new IppResolutionAttribute(IPP_RESOLUTION, name, x, y, u));
859}
860
861void IppContent::setRangeOfInteger(const char *name, int lower, int upper)
862{
863	attrs.push_back(new IppRangeOfIntegerAttribute(IPP_RANGE_OF_INTEGER, name, lower, upper));
864}
865
866void IppContent::setTextWithLanguage(const char *name, const char *s1, const char *s2)
867{
868	attrs.push_back(new IppDoubleStringAttribute(IPP_TEXT_WITH_LANGUAGE, name, s1, s2));
869}
870
871void IppContent::setNameWithLanguage(const char *name, const char *s1, const char *s2)
872{
873	attrs.push_back(new IppDoubleStringAttribute(IPP_NAME_WITH_LANGUAGE, name, s1, s2));
874}
875
876void IppContent::setTextWithoutLanguage(const char *name, const char *value)
877{
878	attrs.push_back(new IppStringAttribute(IPP_TEXT_WITHOUT_LANGUAGE, name, value));
879}
880
881void IppContent::setNameWithoutLanguage(const char *name, const char *value)
882{
883	attrs.push_back(new IppStringAttribute(IPP_NAME_WITHOUT_LANGUAGE, name, value));
884}
885
886void IppContent::setKeyword(const char *name, const char *value)
887{
888	attrs.push_back(new IppStringAttribute(IPP_KEYWORD, name, value));
889}
890
891void IppContent::setURI(const char *name, const char *value)
892{
893	attrs.push_back(new IppStringAttribute(IPP_URI, name, value));
894}
895
896void IppContent::setURIScheme(const char *name, const char *value)
897{
898	attrs.push_back(new IppStringAttribute(IPP_URISCHEME, name, value));
899}
900
901void IppContent::setCharset(const char *name, const char *value)
902{
903	attrs.push_back(new IppStringAttribute(IPP_CHARSET, name, value));
904}
905
906void IppContent::setNaturalLanguage(const char *name, const char *value)
907{
908	attrs.push_back(new IppStringAttribute(IPP_NATURAL_LANGUAGE, name, value));
909}
910
911void IppContent::setMimeMediaType(const char *name, const char *value)
912{
913	attrs.push_back(new IppStringAttribute(IPP_MIME_MEDIA_TYPE, name, value));
914}
915
916int IppContent::length() const
917{
918	int length = 8;	// sizeof(version-number + operation-id + request-id)
919
920	for (list<IppAttribute *>::const_iterator it = attrs.begin(); it != attrs.end(); it++) {
921		length += (*it)->length();
922	}
923
924	ifstream ifs;
925	istream *iss = is;
926	if (iss == NULL) {
927		if (!file_path.empty()) {
928			ifs.open(file_path.c_str(), ios::in | ios::binary);
929			iss = &ifs;
930		}
931	}
932	if (iss && iss->good()) {
933		int fsize = size;
934		if (fsize < 0) {
935			streampos pos = iss->tellg();
936			iss->seekg(0, ios::end);
937			fsize = iss->tellg();
938			iss->seekg(pos, ios::beg);
939		}
940		if (fsize > 0) {
941			length += fsize;
942		}
943	}
944
945	return length;
946}
947
948void IppContent::setRawData(const char *file, int n)
949{
950	file_path = file;
951	size = n;
952}
953
954void IppContent::setRawData(istream &ifs, int n)
955{
956	is = &ifs;
957	size = n;
958}
959
960ostream &IppContent::print(ostream &os) const
961{
962	os << "version:      " << hex << version << '\n';
963	os << "operation_id: " << hex << operation_id << '\n';
964	os << "request_id:   " << hex << request_id << '\n';
965
966	for (list<IppAttribute *>::const_iterator it = attrs.begin(); it != attrs.end(); it++) {
967		(*it)->print(os);
968	}
969
970	return os;
971}
972
973bool IppContent::fail() const
974{
975	return !good();
976}
977
978bool IppContent::good() const
979{
980	return /*operation_id >= IPP_SUCCESSFUL_OK_S &&*/ operation_id <= IPP_SUCCESSFUL_OK_E;
981}
982
983bool IppContent::operator !() const
984{
985	return fail();
986}
987
988const char *IppContent::getStatusMessage() const
989{
990	if (good()) {
991		switch (operation_id) {
992		case IPP_SUCCESSFUL_OK:
993			return "successful-ok";
994		case IPP_SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES:
995			return "successful-ok-ignored-or-substituted-attributes";
996		case IPP_SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES:
997			return "successful-ok-conflicting-attributes";
998		default:
999			return "successful-ok-???";
1000		}
1001	} else if (IPP_CLIENT_ERROR_S <= operation_id && operation_id <= IPP_CLIENT_ERROR_E) {
1002		switch (operation_id) {
1003		case IPP_CLIENT_ERROR_BAD_REQUEST:
1004			return "client-error-bad-request";
1005		case IPP_CLIENT_ERROR_FORBIDDEN:
1006			return "client-error-forbidden";
1007		case IPP_CLIENT_ERROR_NOT_AUTHENTICATED:
1008			return "client-error-not-authenticated";
1009		case IPP_CLIENT_ERROR_NOT_AUTHORIZED:
1010			return "client-error-not-authorized";
1011		case IPP_CLIENT_ERROR_NOT_POSSIBLE:
1012			return "client-error-not-possible";
1013		case IPP_CLIENT_ERROR_TIMEOUT:
1014			return "client-error-timeout";
1015		case IPP_CLIENT_ERROR_NOT_FOUND:
1016			return "client-error-not-found";
1017		case IPP_CLIENT_ERROR_GONE:
1018			return "client-error-gone";
1019		case IPP_CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE:
1020			return "client-error-request-entity-too-large";
1021		case IPP_CLIENT_ERROR_REQUEST_VALUE_TOO_LONG:
1022			return "client-error-request-value-too-long";
1023		case IPP_CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED:
1024			return "client-error-document-format-not-supported";
1025		case IPP_CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED:
1026			return "client-error-attributes-or-values-not-supported";
1027		case IPP_CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED:
1028			return "client-error-uri-scheme-not-supported";
1029		case IPP_CLIENT_ERROR_CHARSET_NOT_SUPPORTED:
1030			return "client-error-charset-not-supported";
1031		case IPP_CLIENT_ERROR_CONFLICTING_ATTRIBUTES:
1032			return "client-error-conflicting-attributes";
1033		default:
1034			return "client-error-???";
1035		}
1036	} else if (IPP_SERVER_ERROR_S <= operation_id && operation_id <= IPP_SERVER_ERROR_E) {
1037		switch (operation_id) {
1038		case IPP_SERVER_ERROR_INTERNAL_ERROR:
1039			return "server-error-internal-error";
1040		case IPP_SERVER_ERROR_OPERATION_NOT_SUPPORTED:
1041			return "server-error-operation-not-supported";
1042		case IPP_SERVER_ERROR_SERVICE_UNAVAILABLE:
1043			return "server-error-service-unavailable";
1044		case IPP_SERVER_ERROR_VERSION_NOT_SUPPORTED:
1045			return "server-error-version-not-supported";
1046		case IPP_SERVER_ERROR_DEVICE_ERROR:
1047			return "server-error-device-error";
1048		case IPP_SERVER_ERROR_TEMPORARY_ERROR:
1049			return "server-error-temporary-error";
1050		case IPP_SERVER_ERROR_NOT_ACCEPTING_JOBS:
1051			return "server-error-not-accepting-jobs";
1052		case IPP_SERVER_ERROR_BUSY:
1053			return "server-error-busy";
1054		case IPP_SERVER_ERROR_JOB_CANCELED:
1055			return "server-error-job-canceled";
1056		default:
1057			return "server-error-???";
1058		}
1059	} else {
1060		return "unknown error.";
1061	}
1062}
1063