#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <papi.h>
#include <ipp.h>
static int8_t
papi_attribute_to_ipp_type(papi_attribute_value_type_t type)
{
switch (type) {
case PAPI_INTEGER:
return (VTAG_INTEGER);
case PAPI_BOOLEAN:
return (VTAG_BOOLEAN);
case PAPI_RANGE:
return (VTAG_RANGE_OF_INTEGER);
case PAPI_RESOLUTION:
return (VTAG_RESOLUTION);
case PAPI_DATETIME:
return (VTAG_DATE_TIME);
case PAPI_STRING:
return (VTAG_TEXT_WITHOUT_LANGUAGE);
}
return (0);
}
static papi_status_t
papi_ipp_type_match(papi_attribute_value_type_t papi, int8_t ipp)
{
switch (papi) {
case PAPI_STRING:
switch (ipp) {
case VTAG_URI:
case VTAG_OCTET_STRING:
case VTAG_TEXT_WITHOUT_LANGUAGE:
case VTAG_URI_SCHEME:
case VTAG_CHARSET:
case VTAG_NATURAL_LANGUAGE:
case VTAG_MIME_MEDIA_TYPE:
case VTAG_NAME_WITHOUT_LANGUAGE:
case VTAG_KEYWORD:
break;
default:
return (PAPI_CONFLICT);
}
break;
case PAPI_INTEGER:
switch (ipp) {
case VTAG_ENUM:
case VTAG_INTEGER:
break;
default:
return (PAPI_CONFLICT);
}
break;
case PAPI_BOOLEAN:
if (ipp != VTAG_BOOLEAN)
return (PAPI_CONFLICT);
break;
case PAPI_RANGE:
if (ipp != VTAG_RANGE_OF_INTEGER)
return (PAPI_CONFLICT);
break;
case PAPI_RESOLUTION:
if (ipp != VTAG_RESOLUTION)
return (PAPI_CONFLICT);
break;
case PAPI_DATETIME:
if (ipp != VTAG_DATE_TIME)
return (PAPI_CONFLICT);
break;
case PAPI_COLLECTION:
break;
}
return (PAPI_OK);
}
static papi_status_t
ipp_write_attribute(ipp_writer_t iwrite, void *fd, papi_attribute_t *attribute)
{
papi_status_t status;
papi_attribute_value_t **values;
int8_t type;
int i;
char *name;
name = attribute->name;
values = attribute->values;
if ((type = name_to_ipp_type(name)) == 0)
type = papi_attribute_to_ipp_type(attribute->type);
if ((status = papi_ipp_type_match(attribute->type, type)) != PAPI_OK)
return (status);
if (values == NULL) {
uint16_t length;
type = VTAG_UNSUPPORTED;
if (iwrite(fd, &type, 1) != 1)
return (PAPI_DEVICE_ERROR);
if (name != NULL) {
length = (uint16_t)htons(strlen(name));
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, name, strlen(name)) != strlen(name))
return (PAPI_DEVICE_ERROR);
}
length = (uint16_t)htons(0);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
return (PAPI_OK);
}
for (i = 0; values[i] != NULL; i++) {
papi_attribute_value_t *value = values[i];
uint16_t length = 0;
if (iwrite(fd, &type, 1) != 1)
return (PAPI_DEVICE_ERROR);
if (name != NULL) {
length = (uint16_t)htons(strlen(name));
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, name, strlen(name)) != strlen(name))
return (PAPI_DEVICE_ERROR);
name = NULL;
} else {
length = (uint16_t)htons(0);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
}
switch (attribute->type) {
case PAPI_STRING: {
char *v = (char *)value->string;
if (v != NULL) {
size_t str_length = strlen(v);
if (str_length > 0xFFFF)
str_length = 0xFFFF;
length = (uint16_t)htons(str_length);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, v, str_length) != str_length)
return (PAPI_DEVICE_ERROR);
} else
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
}
break;
case PAPI_BOOLEAN: {
int8_t v = (int8_t)value->boolean;
length = (uint16_t)htons(1);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &v, 1) != 1)
return (PAPI_DEVICE_ERROR);
}
break;
case PAPI_INTEGER: {
int32_t v = (int32_t)value->integer;
length = (uint16_t)htons(4);
v = (int32_t)htonl(v);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &v, 4) != 4)
return (PAPI_DEVICE_ERROR);
}
break;
case PAPI_RANGE: {
int32_t min = (int32_t)htonl((int)(value->range).lower),
max = (int32_t)htonl((int)(value->range).upper);
length = (uint16_t)htons(8);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &min, 4) != 4)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &max, 4) != 4)
return (PAPI_DEVICE_ERROR);
}
break;
case PAPI_RESOLUTION: {
int32_t x = (int)(value->resolution).xres,
y = (int)(value->resolution).yres;
int8_t units = (int8_t)(value->resolution).units;
length = (uint16_t)htons(9);
x = (int32_t)htonl(x);
y = (int32_t)htonl(y);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &x, 4) != 4)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &y, 4) != 4)
return (PAPI_DEVICE_ERROR);
if (iwrite(fd, &units, 1) != 1)
return (PAPI_DEVICE_ERROR);
}
break;
case PAPI_DATETIME: {
struct tm *v = gmtime(&value->datetime);
int8_t c;
uint16_t s;
length = (uint16_t)htons(11);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
s = (uint16_t)htons(v->tm_year + 1900);
if (iwrite(fd, &s, 2) != 2)
return (PAPI_DEVICE_ERROR);
c = v->tm_mon + 1;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = v->tm_mday;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = v->tm_hour;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = v->tm_min;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = v->tm_sec;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = 0;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = 0;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = 0;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
c = 0;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
}
break;
default: {
length = (uint16_t)htons(0);
if (iwrite(fd, &length, 2) != 2)
return (PAPI_DEVICE_ERROR);
}
break;
}
}
return (PAPI_OK);
}
static papi_status_t
ipp_write_attribute_group(ipp_writer_t iwrite, void *fd, int8_t type,
papi_attribute_t **attributes)
{
papi_status_t result = PAPI_OK;
int i;
if (iwrite(fd, &type, 1) != 1)
return (PAPI_DEVICE_ERROR);
for (i = 0; ((attributes[i] != NULL) && (result == PAPI_OK)); i++)
result = ipp_write_attribute(iwrite, fd, attributes[i]);
return (result);
}
static papi_status_t
ipp_write_attribute_groups(ipp_writer_t iwrite, void *fd,
papi_attribute_t **groups)
{
papi_status_t result = PAPI_OK;
int8_t c;
for (c = DTAG_MIN; c <= DTAG_MAX; c++) {
papi_status_t status;
papi_attribute_t **group = NULL;
void *iter = NULL;
char name[32];
(void) ipp_tag_string(c, name, sizeof (name));
for (status = papiAttributeListGetCollection(groups, &iter,
name, &group);
((status == PAPI_OK) && (result == PAPI_OK));
status = papiAttributeListGetCollection(groups, &iter,
NULL, &group))
result = ipp_write_attribute_group(iwrite, fd,
c, group);
}
c = DTAG_END_OF_ATTRIBUTES;
if (iwrite(fd, &c, 1) != 1)
result = PAPI_DEVICE_ERROR;
return (result);
}
static papi_status_t
ipp_write_message_header(ipp_writer_t iwrite, void *fd,
papi_attribute_t **message)
{
int tmp;
int8_t c;
uint16_t s;
int32_t i;
papiAttributeListGetInteger(message, NULL, "version-major", &tmp);
c = tmp;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
papiAttributeListGetInteger(message, NULL, "version-minor", &tmp);
c = tmp;
if (iwrite(fd, &c, 1) != 1)
return (PAPI_DEVICE_ERROR);
papiAttributeListGetInteger(message, NULL, "status-code", &tmp);
papiAttributeListGetInteger(message, NULL, "operation-id", &tmp);
s = (uint16_t)htons(tmp);
if (iwrite(fd, &s, 2) != 2)
return (PAPI_DEVICE_ERROR);
papiAttributeListGetInteger(message, NULL, "request-id", &tmp);
i = (uint32_t)htonl(tmp);
if (iwrite(fd, &i, 4) != 4)
return (PAPI_DEVICE_ERROR);
return (PAPI_OK);
}
papi_status_t
ipp_write_message(ipp_writer_t iwrite, void *fd, papi_attribute_t **message)
{
papi_status_t result;
if ((iwrite == NULL) || (fd == NULL) || (message == NULL))
return (PAPI_BAD_ARGUMENT);
result = ipp_write_message_header(iwrite, fd, message);
if (result == PAPI_OK)
result = ipp_write_attribute_groups(iwrite, fd, message);
return (result);
}