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