XML_SetAttlistDeclHandler(XML_Parser parser,
                          XML_AttlistDeclHandler attdecl)
{
  if (parser != NULL)
    attlistDeclHandler = attdecl;
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
                                         const char *start,
                                         const char *end,
                                         const char **endPtr);

static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);

static enum XML_Error
processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
               const char *s, const char *next);

static enum XML_Error
initializeEncoding(XML_Parser parser);

static enum XML_Error
doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
         const char *end, int tok, const char *next, const char **nextPtr,
         XML_Bool haveMore);

static enum XML_Error
processInternalEntity(XML_Parser parser, ENTITY *entity,
                      XML_Bool betweenDecl);

static enum XML_Error
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
          const char *start, const char *end, const char **endPtr,
          XML_Bool haveMore);

static enum XML_Error
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
               const char *end, const char **nextPtr, XML_Bool haveMore);

static enum XML_Error
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
                const char *end, const char **nextPtr, XML_Bool haveMore);

static void
freeBindings(XML_Parser parser, BINDING *bindings);

static enum XML_Error
storeAtts(XML_Parser parser, const ENCODING *, const char *s,
          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);

static enum XML_Error
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
           const XML_Char *uri, BINDING **bindingsPtr);

static int
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);

static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                    const char *, const char *, STRING_POOL *);

static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                     const char *, const char *, STRING_POOL *);

static ATTRIBUTE_ID *
getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
               const char *end);

static int
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);

static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
                 const char *end);

static int
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
                            const char *start, const char *end);

static int
reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
              const char *end);

static void
reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
              const char *end);

static const XML_Char * getContext(XML_Parser parser);

static XML_Bool
setContext(XML_Parser parser, const XML_Char *context);

static int
dtdCopy(XML_Parser oldParser,
        DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);

static int
copyEntityTable(XML_Parser oldParser,
                HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);

static NAMED *
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);


XML_GetInputContext(XML_Parser parser, int *offset, int *size)
{
#ifdef XML_CONTEXT_BYTES
  if (parser == NULL)
    return NULL;
  if (eventPtr && buffer) {
    if (offset != NULL)
      *offset = (int)(eventPtr - buffer);
    if (size != NULL)
      *size   = (int)(bufferEnd - buffer);
    return buffer;
  }
#else
  (void)parser;
  (void)offset;
  (void)size;
#endif /* defined XML_CONTEXT_BYTES */
  return (char *) 0;
}

xmlparse.c: Fix external entity infinite loop bug (CVE-2017-9233)

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef char ICHAR;

typedef struct {
  NAMED **v;
  unsigned char power;
  size_t size;
  size_t used;
  const XML_Memory_Handling_Suite *mem;
} HASH_TABLE;

#define CHAR_HASH(h, c) \
  (((h) * 0xF4243) ^ (unsigned char)(c))

#define PROBE_STEP(hash, mask, power) \
  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))

typedef struct binding {
  struct prefix *prefix;
  struct binding *nextTagBinding;
  struct binding *prevPrefixBinding;
  const struct attribute_id *attId;
  XML_Char *uri;
  int uriLen;
  int uriAlloc;
} BINDING;

typedef struct {
  const XML_Char *str;
  const XML_Char *localPart;
  const XML_Char *prefix;
  int strLen;
  int uriLen;
  int prefixLen;
} TAG_NAME;

typedef struct tag {
  struct tag *parent;           /* parent of this element */
  const char *rawName;          /* tagName in the original encoding */
  int rawNameLength;
  TAG_NAME name;                /* tagName in the API encoding */
  char *buf;                    /* buffer for name components */
  char *bufEnd;                 /* end of the buffer */
  BINDING *bindings;
} TAG;

typedef struct {
  const XML_Char *name;
  const XML_Char *textPtr;
  int textLen;                  /* length in XML_Chars */
  int processed;                /* # of processed bytes - when suspended */
  const XML_Char *systemId;
  const XML_Char *base;
  const XML_Char *publicId;
  const XML_Char *notation;
  XML_Bool open;
  XML_Bool is_param;
  XML_Bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;

typedef struct {
  enum XML_Content_Type         type;
  enum XML_Content_Quant        quant;
  const XML_Char *              name;
  int                           firstchild;
  int                           lastchild;
  int                           childcnt;
  int                           nextsib;
} CONTENT_SCAFFOLD;

typedef struct block {
  struct block *next;
  int size;
  XML_Char s[1];
} BLOCK;

typedef struct {
  const XML_Char *name;
  PREFIX *prefix;
  const ATTRIBUTE_ID *idAtt;
  int nDefaultAtts;
  int allocDefaultAtts;
  DEFAULT_ATTRIBUTE *defaultAtts;
} ELEMENT_TYPE;

typedef struct {
  HASH_TABLE generalEntities;
  HASH_TABLE elementTypes;
  HASH_TABLE attributeIds;
  HASH_TABLE prefixes;
  STRING_POOL pool;
  STRING_POOL entityValuePool;
  /* false once a parameter entity reference has been skipped */
  XML_Bool keepProcessing;
  /* true once an internal or external PE reference has been encountered;
     this includes the reference to an external subset */
  XML_Bool hasParamEntityRefs;
  XML_Bool standalone;
#ifdef XML_DTD
  /* indicates if external PE has been read */
  XML_Bool paramEntityRead;
  HASH_TABLE paramEntities;
#endif /* XML_DTD */
  PREFIX defaultPrefix;
  /* === scaffolding for building content model === */
  XML_Bool in_eldecl;
  CONTENT_SCAFFOLD *scaffold;
  unsigned contentStringLen;
  unsigned scaffSize;
  unsigned scaffCount;
  int scaffLevel;
  int *scaffIndex;
} DTD;


poolGrow(STRING_POOL *pool)
{
  if (pool->freeBlocks) {
    if (pool->start == 0) {
      pool->blocks = pool->freeBlocks;
      pool->freeBlocks = pool->freeBlocks->next;
      pool->blocks->next = NULL;
      pool->start = pool->blocks->s;
      pool->end = pool->start + pool->blocks->size;
      pool->ptr = pool->start;
      return XML_TRUE;
    }
    if (pool->end - pool->start < pool->freeBlocks->size) {
      BLOCK *tem = pool->freeBlocks->next;
      pool->freeBlocks->next = pool->blocks;
      pool->blocks = pool->freeBlocks;
      pool->freeBlocks = tem;
      memcpy(pool->blocks->s, pool->start,
             (pool->end - pool->start) * sizeof(XML_Char));
      pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
      pool->start = pool->blocks->s;
      pool->end = pool->start + pool->blocks->size;
      return XML_TRUE;
    }
  }
  if (pool->blocks && pool->start == pool->blocks->s) {
    BLOCK *temp;
    int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
    size_t bytesToAllocate;

    if (blockSize < 0)
      return XML_FALSE;

    bytesToAllocate = poolBytesToAllocateFor(blockSize);
    if (bytesToAllocate == 0)
      return XML_FALSE;

    temp = (BLOCK *)
      pool->mem->realloc_fcn(pool->blocks, (unsigned)bytesToAllocate);
    if (temp == NULL)
      return XML_FALSE;
    pool->blocks = temp;
    pool->blocks->size = blockSize;
    pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
    pool->start = pool->blocks->s;
    pool->end = pool->start + blockSize;
  }
  else {
    BLOCK *tem;
    int blockSize = (int)(pool->end - pool->start);
    size_t bytesToAllocate;

    if (blockSize < 0)
      return XML_FALSE;

    if (blockSize < INIT_BLOCK_SIZE)
      blockSize = INIT_BLOCK_SIZE;
    else {
      /* Detect overflow, avoiding _signed_ overflow undefined behavior */
      if ((int)((unsigned)blockSize * 2U) < 0) {
        return XML_FALSE;
      }
      blockSize *= 2;
    }

    bytesToAllocate = poolBytesToAllocateFor(blockSize);
    if (bytesToAllocate == 0)
      return XML_FALSE;

    tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
    if (!tem)
      return XML_FALSE;
    tem->size = blockSize;
    tem->next = pool->blocks;
    pool->blocks = tem;
    if (pool->ptr != pool->start)
      memcpy(tem->s, pool->start,
             (pool->ptr - pool->start) * sizeof(XML_Char));
    pool->ptr = tem->s + (pool->ptr - pool->start);
    pool->start = tem->s;
    pool->end = tem->s + blockSize;
  }
  return XML_TRUE;
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef unsigned short ICHAR;

#define XML_T(x) (const unsigned short)x

typedef const XML_Char *KEY;

typedef struct {
  NAMED **v;
  unsigned char power;
  size_t size;
  size_t used;
  const XML_Memory_Handling_Suite *mem;
} HASH_TABLE;

#define CHAR_HASH(h, c) \
  (((h) * 0xF4243) ^ (unsigned short)(c))

#define CHAR_HASH(h, c) \
  (((h) * 0xF4243) ^ (unsigned char)(c))

#define PROBE_STEP(hash, mask, power) \
  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))

typedef struct {
  NAMED **p;
  NAMED **end;
} HASH_TABLE_ITER;

#define INIT_TAG_BUF_SIZE 32  /* must be a multiple of sizeof(XML_Char) */

#define INIT_BLOCK_SIZE 1024

typedef struct binding {
  struct prefix *prefix;
  struct binding *nextTagBinding;
  struct binding *prevPrefixBinding;
  const struct attribute_id *attId;
  XML_Char *uri;
  int uriLen;
  int uriAlloc;
} BINDING;

typedef struct prefix {
  const XML_Char *name;
  BINDING *binding;
} PREFIX;

typedef struct {
  const XML_Char *str;
  const XML_Char *localPart;
  const XML_Char *prefix;
  int strLen;
  int uriLen;
  int prefixLen;
} TAG_NAME;

typedef struct tag {
  struct tag *parent;           /* parent of this element */
  const char *rawName;          /* tagName in the original encoding */
  int rawNameLength;
  TAG_NAME name;                /* tagName in the API encoding */
  char *buf;                    /* buffer for name components */
  char *bufEnd;                 /* end of the buffer */
  BINDING *bindings;
} TAG;

typedef struct {
  const XML_Char *name;
  const XML_Char *textPtr;
  int textLen;                  /* length in XML_Chars */
  int processed;                /* # of processed bytes - when suspended */
  const XML_Char *systemId;
  const XML_Char *base;
  const XML_Char *publicId;
  const XML_Char *notation;
  XML_Bool open;
  XML_Bool is_param;
  XML_Bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;

typedef struct {
  enum XML_Content_Type         type;
  enum XML_Content_Quant        quant;
  const XML_Char *              name;
  int                           firstchild;
  int                           lastchild;
  int                           childcnt;
  int                           nextsib;
} CONTENT_SCAFFOLD;

typedef struct block {
  struct block *next;
  int size;
  XML_Char s[1];
} BLOCK;

typedef struct {
  BLOCK *blocks;
  BLOCK *freeBlocks;
  const XML_Char *end;
  XML_Char *ptr;
  XML_Char *start;
  const XML_Memory_Handling_Suite *mem;
} STRING_POOL;

typedef struct attribute_id {
  XML_Char *name;
  PREFIX *prefix;
  XML_Bool maybeTokenized;
  XML_Bool xmlns;
} ATTRIBUTE_ID;

typedef struct {
  const ATTRIBUTE_ID *id;
  XML_Bool isCdata;
  const XML_Char *value;
} DEFAULT_ATTRIBUTE;

typedef struct {
  unsigned long version;
  unsigned long hash;
  const XML_Char *uriName;
} NS_ATT;


XML_SetStartElementHandler(XML_Parser parser,
                           XML_StartElementHandler start) {
  if (parser != NULL)
    startElementHandler = start;
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef struct {
  BLOCK *blocks;
  BLOCK *freeBlocks;
  const XML_Char *end;
  XML_Char *ptr;
  XML_Char *start;
  const XML_Memory_Handling_Suite *mem;
} STRING_POOL;

typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
                                         const char *start,
                                         const char *end,
                                         const char **endPtr);

static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);

static enum XML_Error
processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
               const char *s, const char *next);

static enum XML_Error
initializeEncoding(XML_Parser parser);

static enum XML_Error
doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
         const char *end, int tok, const char *next, const char **nextPtr,
         XML_Bool haveMore);

static enum XML_Error
processInternalEntity(XML_Parser parser, ENTITY *entity,
                      XML_Bool betweenDecl);

static enum XML_Error
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
          const char *start, const char *end, const char **endPtr,
          XML_Bool haveMore);

static enum XML_Error
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
               const char *end, const char **nextPtr, XML_Bool haveMore);

static enum XML_Error
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
                const char *end, const char **nextPtr, XML_Bool haveMore);

static void
freeBindings(XML_Parser parser, BINDING *bindings);

static enum XML_Error
storeAtts(XML_Parser parser, const ENCODING *, const char *s,
          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);

static enum XML_Error
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
           const XML_Char *uri, BINDING **bindingsPtr);

static int
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);

static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                    const char *, const char *, STRING_POOL *);

static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                     const char *, const char *, STRING_POOL *);

static ATTRIBUTE_ID *
getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
               const char *end);

static int
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);

static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
                 const char *end);

static int
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
                            const char *start, const char *end);

static int
reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
              const char *end);

static void
reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
              const char *end);

static const XML_Char * getContext(XML_Parser parser);

static XML_Bool
setContext(XML_Parser parser, const XML_Char *context);

static int
dtdCopy(XML_Parser oldParser,
        DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);


XML_SetNamespaceDeclHandler(XML_Parser parser,
                            XML_StartNamespaceDeclHandler start,
                            XML_EndNamespaceDeclHandler end)
{
  if (parser == NULL)
    return;
  startNamespaceDeclHandler = start;
  endNamespaceDeclHandler = end;
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef struct {
  NAMED **p;
  NAMED **end;
} HASH_TABLE_ITER;

typedef struct tag {
  struct tag *parent;           /* parent of this element */
  const char *rawName;          /* tagName in the original encoding */
  int rawNameLength;
  TAG_NAME name;                /* tagName in the API encoding */
  char *buf;                    /* buffer for name components */
  char *bufEnd;                 /* end of the buffer */
  BINDING *bindings;
} TAG;

typedef struct {
  BLOCK *blocks;
  BLOCK *freeBlocks;
  const XML_Char *end;
  XML_Char *ptr;
  XML_Char *start;
  const XML_Memory_Handling_Suite *mem;
} STRING_POOL;

typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
                                         const char *start,
                                         const char *end,
                                         const char **endPtr);

static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);

static enum XML_Error
processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
               const char *s, const char *next);

static enum XML_Error
initializeEncoding(XML_Parser parser);

static enum XML_Error
doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
         const char *end, int tok, const char *next, const char **nextPtr,
         XML_Bool haveMore);

static enum XML_Error
processInternalEntity(XML_Parser parser, ENTITY *entity,
                      XML_Bool betweenDecl);

static enum XML_Error
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
          const char *start, const char *end, const char **endPtr,
          XML_Bool haveMore);

static enum XML_Error
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
               const char *end, const char **nextPtr, XML_Bool haveMore);

static enum XML_Error
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
                const char *end, const char **nextPtr, XML_Bool haveMore);

static void
freeBindings(XML_Parser parser, BINDING *bindings);

static enum XML_Error
storeAtts(XML_Parser parser, const ENCODING *, const char *s,
          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);

static enum XML_Error
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
           const XML_Char *uri, BINDING **bindingsPtr);

static int
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);

static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                    const char *, const char *, STRING_POOL *);

static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
                     const char *, const char *, STRING_POOL *);

static ATTRIBUTE_ID *
getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
               const char *end);

static int
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);

static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
                 const char *end);

static int
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
                            const char *start, const char *end);


XML_SetEndDoctypeDeclHandler(XML_Parser parser,
                             XML_EndDoctypeDeclHandler end) {
  if (parser != NULL)
    endDoctypeDeclHandler = end;
}


gather_time_entropy(void)
{
#ifdef _WIN32
  FILETIME ft;
  GetSystemTimeAsFileTime(&ft); /* never fails */
  return ft.dwHighDateTime ^ ft.dwLowDateTime;
#else
  struct timeval tv;
  int gettimeofday_res;

  gettimeofday_res = gettimeofday(&tv, NULL);
  assert (gettimeofday_res == 0);

  /* Microseconds time is <20 bits entropy */
  return tv.tv_usec;
#endif
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef struct {
  KEY name;
} NAMED;

typedef struct {
  NAMED **v;
  unsigned char power;
  size_t size;
  size_t used;
  const XML_Memory_Handling_Suite *mem;
} HASH_TABLE;

typedef struct {
  NAMED **p;
  NAMED **end;
} HASH_TABLE_ITER;

typedef struct binding {
  struct prefix *prefix;
  struct binding *nextTagBinding;
  struct binding *prevPrefixBinding;
  const struct attribute_id *attId;
  XML_Char *uri;
  int uriLen;
  int uriAlloc;
} BINDING;

typedef struct prefix {
  const XML_Char *name;
  BINDING *binding;
} PREFIX;

typedef struct {
  const XML_Char *str;
  const XML_Char *localPart;
  const XML_Char *prefix;
  int strLen;
  int uriLen;
  int prefixLen;
} TAG_NAME;

typedef struct tag {
  struct tag *parent;           /* parent of this element */
  const char *rawName;          /* tagName in the original encoding */
  int rawNameLength;
  TAG_NAME name;                /* tagName in the API encoding */
  char *buf;                    /* buffer for name components */
  char *bufEnd;                 /* end of the buffer */
  BINDING *bindings;
} TAG;

typedef struct {
  const XML_Char *name;
  const XML_Char *textPtr;
  int textLen;                  /* length in XML_Chars */
  int processed;                /* # of processed bytes - when suspended */
  const XML_Char *systemId;
  const XML_Char *base;
  const XML_Char *publicId;
  const XML_Char *notation;
  XML_Bool open;
  XML_Bool is_param;
  XML_Bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;

typedef struct {
  enum XML_Content_Type         type;
  enum XML_Content_Quant        quant;
  const XML_Char *              name;
  int                           firstchild;
  int                           lastchild;
  int                           childcnt;
  int                           nextsib;
} CONTENT_SCAFFOLD;

typedef struct block {
  struct block *next;
  int size;
  XML_Char s[1];
} BLOCK;

typedef struct {
  BLOCK *blocks;
  BLOCK *freeBlocks;
  const XML_Char *end;
  XML_Char *ptr;
  XML_Char *start;
  const XML_Memory_Handling_Suite *mem;
} STRING_POOL;

typedef struct attribute_id {
  XML_Char *name;
  PREFIX *prefix;
  XML_Bool maybeTokenized;
  XML_Bool xmlns;
} ATTRIBUTE_ID;

typedef struct {
  const ATTRIBUTE_ID *id;
  XML_Bool isCdata;
  const XML_Char *value;
} DEFAULT_ATTRIBUTE;

typedef struct {
  unsigned long version;
  unsigned long hash;
  const XML_Char *uriName;
} NS_ATT;

typedef struct {
  const XML_Char *name;
  PREFIX *prefix;
  const ATTRIBUTE_ID *idAtt;
  int nDefaultAtts;
  int allocDefaultAtts;
  DEFAULT_ATTRIBUTE *defaultAtts;
} ELEMENT_TYPE;


XML_GetCurrentByteCount(XML_Parser parser)
{
  if (parser == NULL)
    return 0;
  if (eventEndPtr && eventPtr)
    return (int)(eventEndPtr - eventPtr);
  return 0;
}

#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))

typedef struct binding {
  struct prefix *prefix;
  struct binding *nextTagBinding;
  struct binding *prevPrefixBinding;
  const struct attribute_id *attId;
  XML_Char *uri;
  int uriLen;
  int uriAlloc;
} BINDING;

typedef struct {
  const XML_Char *str;
  const XML_Char *localPart;
  const XML_Char *prefix;
  int strLen;
  int uriLen;
  int prefixLen;
} TAG_NAME;

typedef struct tag {
  struct tag *parent;           /* parent of this element */
  const char *rawName;          /* tagName in the original encoding */
  int rawNameLength;
  TAG_NAME name;                /* tagName in the API encoding */
  char *buf;                    /* buffer for name components */
  char *bufEnd;                 /* end of the buffer */
  BINDING *bindings;
} TAG;

typedef struct {
  const XML_Char *name;
  const XML_Char *textPtr;
  int textLen;                  /* length in XML_Chars */
  int processed;                /* # of processed bytes - when suspended */
  const XML_Char *systemId;
  const XML_Char *base;
  const XML_Char *publicId;
  const XML_Char *notation;
  XML_Bool open;
  XML_Bool is_param;
  XML_Bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;

typedef struct {
  enum XML_Content_Type         type;
  enum XML_Content_Quant        quant;
  const XML_Char *              name;
  int                           firstchild;
  int                           lastchild;
  int                           childcnt;
  int                           nextsib;
} CONTENT_SCAFFOLD;

typedef struct block {
  struct block *next;
  int size;
  XML_Char s[1];
} BLOCK;

typedef struct {
  const XML_Char *name;
  PREFIX *prefix;
  const ATTRIBUTE_ID *idAtt;
  int nDefaultAtts;
  int allocDefaultAtts;
  DEFAULT_ATTRIBUTE *defaultAtts;
} ELEMENT_TYPE;

typedef struct {
  HASH_TABLE generalEntities;
  HASH_TABLE elementTypes;
  HASH_TABLE attributeIds;
  HASH_TABLE prefixes;
  STRING_POOL pool;
  STRING_POOL entityValuePool;
  /* false once a parameter entity reference has been skipped */
  XML_Bool keepProcessing;
  /* true once an internal or external PE reference has been encountered;
     this includes the reference to an external subset */
  XML_Bool hasParamEntityRefs;
  XML_Bool standalone;
#ifdef XML_DTD
  /* indicates if external PE has been read */
  XML_Bool paramEntityRead;
  HASH_TABLE paramEntities;
#endif /* XML_DTD */
  PREFIX defaultPrefix;
  /* === scaffolding for building content model === */
  XML_Bool in_eldecl;
  CONTENT_SCAFFOLD *scaffold;
  unsigned contentStringLen;
  unsigned scaffSize;
  unsigned scaffCount;
  int scaffLevel;
  int *scaffIndex;
} DTD;

typedef struct open_internal_entity {
  const char *internalEventPtr;
  const char *internalEventEndPtr;
  struct open_internal_entity *next;
  ENTITY *entity;
  int startTagLevel;
  XML_Bool betweenDecl; /* WFC: PE Between Declarations */
} OPEN_INTERNAL_ENTITY;

typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
                                         const char *start,
                                         const char *end,
                                         const char **endPtr);

static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);

static enum XML_Error
processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
               const char *s, const char *next);

static enum XML_Error
initializeEncoding(XML_Parser parser);


int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
{
	const char *ctl;
	uint32_t idx;
	int i;

	for (idx = 0; list[idx].n.len != 0; idx++) {
		if (!list[idx].n.ptr) {
			/* This is an indexed pseudo-header (RFC7540#8.1.2.1) */
			goto fail;
		}

		/* RFC7540#8.1.2: upper case not allowed in header field names.
		 * #10.3: header names must be valid (i.e. match a token). This
		 * also catches pseudo-headers which are forbidden in trailers.
		 */
		for (i = 0; i < list[idx].n.len; i++)
			if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
				goto fail;

		/* these ones are forbidden in trailers (RFC7540#8.1.2.2) */
		if (isteq(list[idx].n, ist("host")) ||
		    isteq(list[idx].n, ist("content-length")) ||
		    isteq(list[idx].n, ist("connection")) ||
		    isteq(list[idx].n, ist("proxy-connection")) ||
		    isteq(list[idx].n, ist("keep-alive")) ||
		    isteq(list[idx].n, ist("upgrade")) ||
		    isteq(list[idx].n, ist("te")) ||
		    isteq(list[idx].n, ist("transfer-encoding")))
			goto fail;

		/* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
		 * rejecting NUL, CR and LF characters.
		 */
		ctl = ist_find_ctl(list[idx].v);
		if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
			goto fail;

		if (!htx_add_trailer(htx, list[idx].n, list[idx].v))
			goto fail;
	}

	if (!htx_add_endof(htx, HTX_BLK_EOT))
		goto fail;

	return 1;

 fail:
	return -1;
}

BUG/MEDIUM: h2: give :authority precedence over Host

The wording regarding Host vs :authority in RFC7540 is ambiguous as it
says that an intermediary must produce a host header from :authority if
Host is missing, but, contrary to HTTP/1.1, doesn't say anything regarding
the possibility that Host and :authority differ, which leaves Host with
higher precedence there. In addition it mentions that clients should use
:authority *instead* of Host, and that H1->H2 should use :authority only
if the original request was in authority form. This leaves some gray
area in the middle of the chain for fully valid H2 requests arboring a
Host header that are forwarded to the other side where it's possible to
drop the Host header and use the authority only after forwarding to a
second H2 layer, thus possibly seeing two different values of Host at
a different stage. There's no such issue when forwarding from H2 to H1
as the authority is dropped only only the Host is kept.

Note that the following request is sufficient to re-normalize such a
request:

   http-request set-header host %[req.hdr(host)]

The new spec in progress (draft-ietf-httpbis-http2bis-03) addresses
this trouble by being a bit is stricter on these rules. It clarifies
that :authority must always be used instead of Host and that Host ought
to be ignored. This is much saner as it avoids to convey two distinct
values along the chain. This becomes the protocol-level equivalent of:

   http-request set-uri %[url]

So this patch does exactly this, which we were initially a bit reluctant
to do initially by lack of visibility about other implementations'
expectations. In addition it slightly simplifies the Host header field
creation by always placing it first in the list of headers instead of
last; this could also speed up the look up a little bit.

This needs to be backported to 2.0. Non-HTX versions are safe regarding
this because they drop the URI during the conversion to HTTP/1.1 so
only Host is used and transmitted.

Thanks to Tim D�sterhus for reporting that one.

struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES] =	{
	 [H2_FT_DATA         ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
	 [H2_FT_HEADERS      ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 1, .max_len = H2_MAX_FRAME_LEN, },
	 [H2_FT_PRIORITY     ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 5, .max_len = 5,                },
	 [H2_FT_RST_STREAM   ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = 4,                },
	 [H2_FT_SETTINGS     ] = { .dir = 3, .min_id = 0, .max_id = 0,                .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
	 [H2_FT_PUSH_PROMISE ] = { .dir = 0, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = H2_MAX_FRAME_LEN, },
	 [H2_FT_PING         ] = { .dir = 3, .min_id = 0, .max_id = 0,                .min_len = 8, .max_len = 8,                },
	 [H2_FT_GOAWAY       ] = { .dir = 3, .min_id = 0, .max_id = 0,                .min_len = 8, .max_len = H2_MAX_FRAME_LEN, },
	 [H2_FT_WINDOW_UPDATE] = { .dir = 3, .min_id = 0, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = 4,                },
	 [H2_FT_CONTINUATION ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
};


static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr, struct htx *htx, unsigned int *msgf)
{
	struct ist uri, meth_sl;
	unsigned int flags = HTX_SL_F_NONE;
	struct htx_sl *sl;
	size_t i;

	if ((fields & H2_PHDR_FND_METH) && isteq(phdr[H2_PHDR_IDX_METH], ist("CONNECT"))) {
		if (fields & H2_PHDR_FND_PROT) {
			/* rfc 8441 Extended Connect Protocol
			 * #4 :scheme and :path must be present, as well as
			 * :authority like all h2 requests
			 */
			if (!(fields & H2_PHDR_FND_SCHM)) {
				/* missing scheme */
				goto fail;
			}
			else if (!(fields & H2_PHDR_FND_PATH)) {
				/* missing path */
				goto fail;
			}
			else if (!(fields & H2_PHDR_FND_AUTH)) {
				/* missing authority */
				goto fail;
			}

			flags |= HTX_SL_F_HAS_SCHM;
			if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("http")))
				flags |= HTX_SL_F_SCHM_HTTP;
			else if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("https")))
				flags |= HTX_SL_F_SCHM_HTTPS;
			else if (!http_validate_scheme(phdr[H2_PHDR_IDX_SCHM]))
				htx->flags |= HTX_FL_PARSING_ERROR;

			meth_sl = ist("GET");

			*msgf |= H2_MSGF_EXT_CONNECT;
			/* no ES on the HEADERS frame but no body either for
			 * Extended CONNECT */
			*msgf &= ~H2_MSGF_BODY;
		}
		else {
			/* RFC 7540 #8.2.6 regarding CONNECT: ":scheme" and ":path"
			 * MUST be omitted ; ":authority" contains the host and port
			 * to connect to.
			 */
			if (fields & H2_PHDR_FND_SCHM) {
				/* scheme not allowed */
				goto fail;
			}
			else if (fields & H2_PHDR_FND_PATH) {
				/* path not allowed */
				goto fail;
			}
			else if (!(fields & H2_PHDR_FND_AUTH)) {
				/* missing authority */
				goto fail;
			}

			meth_sl = phdr[H2_PHDR_IDX_METH];
		}

		*msgf |= H2_MSGF_BODY_TUNNEL;
	}
	else if ((fields & (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) !=
	         (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) {
		/* RFC 7540 #8.1.2.3 : all requests MUST include exactly one
		 * valid value for the ":method", ":scheme" and ":path" phdr
		 * unless it is a CONNECT request.
		 */
		if (!(fields & H2_PHDR_FND_METH)) {
			/* missing method */
			goto fail;
		}
		else if (!(fields & H2_PHDR_FND_SCHM)) {
			/* missing scheme */
			goto fail;
		}
		else {
			/* missing path */
			goto fail;
		}
	}
	else { /* regular methods */
		/* RFC3986#6.2.2.1: scheme is case-insensitive. We need to
		 * classify the scheme as "present/http", "present/https",
		 * "present/other", "absent" so as to decide whether or not
		 * we're facing a normalized URI that will have to be encoded
		 * in origin or absolute form. Indeed, 7540#8.1.2.3 says that
		 * clients should use the absolute form, thus we cannot infer
		 * whether or not the client wanted to use a proxy here.
		 */
		flags |= HTX_SL_F_HAS_SCHM;
		if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("http")))
			flags |= HTX_SL_F_SCHM_HTTP;
		else if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("https")))
			flags |= HTX_SL_F_SCHM_HTTPS;
		else if (!http_validate_scheme(phdr[H2_PHDR_IDX_SCHM]))
			htx->flags |= HTX_FL_PARSING_ERROR;

		meth_sl = phdr[H2_PHDR_IDX_METH];
	}

	if (fields & H2_PHDR_FND_PATH) {
		/* 7540#8.1.2.3: :path must not be empty, and must be either
		 * '*' or an RFC3986 "path-absolute" starting with a "/" but
		 * not with "//".
		 */
		if (unlikely(!phdr[H2_PHDR_IDX_PATH].len))
			goto fail;
		else if (unlikely(phdr[H2_PHDR_IDX_PATH].ptr[0] != '/')) {
			if (!isteq(phdr[H2_PHDR_IDX_PATH], ist("*")))
				goto fail;
		}
		else if (phdr[H2_PHDR_IDX_PATH].len > 1 &&
			 phdr[H2_PHDR_IDX_PATH].ptr[1] == '/')
			goto fail;
	}

	if (!(flags & HTX_SL_F_HAS_SCHM)) {
		/* no scheme, use authority only (CONNECT) */
		uri = phdr[H2_PHDR_IDX_AUTH];
		flags |= HTX_SL_F_HAS_AUTHORITY;
	}
	else if (fields & H2_PHDR_FND_AUTH) {
		/* authority is present, let's use the absolute form. We simply
		 * use the trash to concatenate them since all of them MUST fit
		 * in a bufsize since it's where they come from.
		 */
		uri = ist2bin(trash.area, phdr[H2_PHDR_IDX_SCHM]);
		istcat(&uri, ist("://"), trash.size);
		istcat(&uri, phdr[H2_PHDR_IDX_AUTH], trash.size);
		if (!isteq(phdr[H2_PHDR_IDX_PATH], ist("*")))
			istcat(&uri, phdr[H2_PHDR_IDX_PATH], trash.size);
		flags |= HTX_SL_F_HAS_AUTHORITY;

		if (flags & (HTX_SL_F_SCHM_HTTP|HTX_SL_F_SCHM_HTTPS)) {
			/* we don't know if it was originally an absolute or a
			 * relative request because newer versions of HTTP use
			 * the absolute URI format by default, which we call
			 * the normalized URI format internally. This is the
			 * strongly recommended way of sending a request for
			 * a regular client, so we cannot distinguish this
			 * from a request intended for a proxy. For other
			 * schemes however there is no doubt.
			 */
			flags |= HTX_SL_F_NORMALIZED_URI;
		}
	}
	else {
		/* usual schemes with or without authority, use origin form */
		uri = phdr[H2_PHDR_IDX_PATH];
		if (fields & H2_PHDR_FND_AUTH)
			flags |= HTX_SL_F_HAS_AUTHORITY;
	}

	/* The method is a non-empty token (RFC7231#4.1) */
	if (!meth_sl.len)
		goto fail;
	for (i = 0; i < meth_sl.len; i++) {
		if (!HTTP_IS_TOKEN(meth_sl.ptr[i]))
			htx->flags |= HTX_FL_PARSING_ERROR;
	}

	/* make sure the final URI isn't empty. Note that 7540#8.1.2.3 states
	 * that :path must not be empty.
	 */
	if (!uri.len)
		goto fail;

	/* The final URI must not contain LWS nor CTL characters */
	for (i = 0; i < uri.len; i++) {
		unsigned char c = uri.ptr[i];
		if (HTTP_IS_LWS(c) || HTTP_IS_CTL(c))
			htx->flags |= HTX_FL_PARSING_ERROR;
	}

	/* Set HTX start-line flags */
	flags |= HTX_SL_F_VER_11;    // V2 in fact
	flags |= HTX_SL_F_XFER_LEN;  // xfer len always known with H2

	sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth_sl, uri, ist("HTTP/2.0"));
	if (!sl)
		goto fail;

	sl->info.req.meth = find_http_meth(meth_sl.ptr, meth_sl.len);
	if (sl->info.req.meth == HTTP_METH_HEAD)
		*msgf |= H2_MSGF_BODYLESS_RSP;
	return sl;
 fail:
	return NULL;
}


static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr, struct htx *htx, unsigned int *msgf)
{
	unsigned int status, flags = HTX_SL_F_NONE;
	struct htx_sl *sl;
	struct ist stat;

	/* only :status is allowed as a pseudo header */
	if (!(fields & H2_PHDR_FND_STAT))
		goto fail;

	if (phdr[H2_PHDR_IDX_STAT].len != 3)
		goto fail;

	/* if Extended CONNECT is used, convert status code from 200 to htx 101
	 * following rfc 8441 */
	if (unlikely(*msgf & H2_MSGF_EXT_CONNECT) &&
	    isteq(phdr[H2_PHDR_IDX_STAT], ist("200"))) {
		stat = ist("101");
		status = 101;
	}
	else {
		unsigned char h, t, u;

		stat = phdr[H2_PHDR_IDX_STAT];

		h = stat.ptr[0] - '0';
		t = stat.ptr[1] - '0';
		u = stat.ptr[2] - '0';
		if (h > 9 || t > 9 || u > 9)
			goto fail;
		status = h * 100 + t * 10 + u;
	}

	/* 101 responses are not supported in H2, so return a error.
	 * On 1xx responses there is no ES on the HEADERS frame but there is no
	 * body. So remove the flag H2_MSGF_BODY and add H2_MSGF_RSP_1XX to
	 * notify the decoder another HEADERS frame is expected.
	 * 204/304 response have no body by definition. So remove the flag
	 * H2_MSGF_BODY and set H2_MSGF_BODYLESS_RSP.
	 *
	 * Note however that there is a special condition for Extended CONNECT.
	 * In this case, we explicitly convert it to HTX 101 to mimic
	 * Get+Upgrade HTTP/1.1 mechanism
	 */
	if (status == 101) {
		if (!(*msgf & H2_MSGF_EXT_CONNECT))
			goto fail;
	}
	else if (status < 200) {
		*msgf |= H2_MSGF_RSP_1XX;
		*msgf &= ~H2_MSGF_BODY;
	}
	else if (status == 204 || status == 304) {
		*msgf &= ~H2_MSGF_BODY;
		*msgf |= H2_MSGF_BODYLESS_RSP;
	}

	/* Set HTX start-line flags */
	flags |= HTX_SL_F_VER_11;    // V2 in fact
	flags |= HTX_SL_F_XFER_LEN;  // xfer len always known with H2

	sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/2.0"), stat, ist(""));
	if (!sl)
		goto fail;
	sl->info.res.status = status;
	return sl;
 fail:
	return NULL;
}


int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned long long *body_len)
{
	char *e, *n;
	unsigned long long cl;
	int not_first = !!(*msgf & H2_MSGF_BODY_CL);
	struct ist word;

	word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
	e = value->ptr + value->len;

	while (++word.ptr < e) {
		/* skip leading delimiter and blanks */
		if (unlikely(HTTP_IS_LWS(*word.ptr)))
			continue;

		/* digits only now */
		for (cl = 0, n = word.ptr; n < e; n++) {
			unsigned int c = *n - '0';
			if (unlikely(c > 9)) {
				/* non-digit */
				if (unlikely(n == word.ptr)) // spaces only
					goto fail;
				break;
			}
			if (unlikely(cl > ULLONG_MAX / 10ULL))
				goto fail; /* multiply overflow */
			cl = cl * 10ULL;
			if (unlikely(cl + c < cl))
				goto fail; /* addition overflow */
			cl = cl + c;
		}

		/* keep a copy of the exact cleaned value */
		word.len = n - word.ptr;

		/* skip trailing LWS till next comma or EOL */
		for (; n < e; n++) {
			if (!HTTP_IS_LWS(*n)) {
				if (unlikely(*n != ','))
					goto fail;
				break;
			}
		}

		/* if duplicate, must be equal */
		if (*msgf & H2_MSGF_BODY_CL && cl != *body_len)
			goto fail;

		/* OK, store this result as the one to be indexed */
		*msgf |= H2_MSGF_BODY_CL;
		*body_len = cl;
		*value = word;
		word.ptr = n;
	}
	/* here we've reached the end with a single value or a series of
	 * identical values, all matching previous series if any. The last
	 * parsed value was sent back into <value>. We just have to decide
	 * if this occurrence has to be indexed (it's the first one) or
	 * silently skipped (it's not the first one)
	 */
	return !not_first;
 fail:
	return -1;
}


int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol)
{
	struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
	uint32_t fields; /* bit mask of H2_PHDR_FND_* */
	uint32_t idx;
	int phdr;
	int ret;
	int i;
	struct htx_sl *sl = NULL;
	unsigned int sl_flags = 0;
	const char *ctl;

	fields = 0;
	for (idx = 0; list[idx].n.len != 0; idx++) {
		if (!list[idx].n.ptr) {
			/* this is an indexed pseudo-header */
			phdr = list[idx].n.len;
		}
		else {
			/* this can be any type of header */
			/* RFC7540#8.1.2: upper case not allowed in header field names.
			 * #10.3: header names must be valid (i.e. match a token).
			 * For pseudo-headers we check from 2nd char and for other ones
			 * from the first char, because HTTP_IS_TOKEN() also excludes
			 * the colon.
			 */
			phdr = h2_str_to_phdr(list[idx].n);

			for (i = !!phdr; i < list[idx].n.len; i++)
				if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
					goto fail;
		}

		/* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
		 * rejecting NUL, CR and LF characters.
		 */
		ctl = ist_find_ctl(list[idx].v);
		if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
			goto fail;

		if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
			/* insert a pseudo header by its index (in phdr) and value (in value) */
			if (fields & ((1 << phdr) | H2_PHDR_FND_NONE)) {
				if (fields & H2_PHDR_FND_NONE) {
					/* pseudo header field after regular headers */
					goto fail;
				}
				else {
					/* repeated pseudo header field */
					goto fail;
				}
			}
			fields |= 1 << phdr;
			phdr_val[phdr] = list[idx].v;
			continue;
		}
		else if (phdr != 0) {
			/* invalid pseudo header -- should never happen here */
			goto fail;
		}

		/* regular header field in (name,value) */
		if (!(fields & H2_PHDR_FND_NONE)) {
			/* no more pseudo-headers, time to build the status line */
			sl = h2_prepare_htx_stsline(fields, phdr_val, htx, msgf);
			if (!sl)
				goto fail;
			fields |= H2_PHDR_FND_NONE;
		}

		if (isteq(list[idx].n, ist("content-length"))) {
			ret = h2_parse_cont_len_header(msgf, &list[idx].v, body_len);
			if (ret < 0)
				goto fail;

			sl_flags |= HTX_SL_F_CLEN;
			if (ret == 0)
				continue; // skip this duplicate
		}

		/* these ones are forbidden in responses (RFC7540#8.1.2.2) */
		if (isteq(list[idx].n, ist("connection")) ||
		    isteq(list[idx].n, ist("proxy-connection")) ||
		    isteq(list[idx].n, ist("keep-alive")) ||
		    isteq(list[idx].n, ist("upgrade")) ||
		    isteq(list[idx].n, ist("transfer-encoding")))
			goto fail;

		if (!htx_add_header(htx, list[idx].n, list[idx].v))
			goto fail;
	}

	/* RFC7540#8.1.2.1 mandates to reject request pseudo-headers */
	if (fields & (H2_PHDR_FND_AUTH|H2_PHDR_FND_METH|H2_PHDR_FND_PATH|H2_PHDR_FND_SCHM))
		goto fail;

	/* Let's dump the request now if not yet emitted. */
	if (!(fields & H2_PHDR_FND_NONE)) {
		sl = h2_prepare_htx_stsline(fields, phdr_val, htx, msgf);
		if (!sl)
			goto fail;
	}

	if (sl->info.res.status == 101 && upgrade_protocol) {
		if (!htx_add_header(htx, ist("connection"), ist("upgrade")))
			goto fail;
		if (!htx_add_header(htx, ist("upgrade"), ist(upgrade_protocol)))
			goto fail;
		sl_flags |= HTX_SL_F_CONN_UPG;
	}

	if ((*msgf & H2_MSGF_BODY_TUNNEL) &&
	    ((sl->info.res.status >= 200 && sl->info.res.status < 300) || sl->info.res.status == 101))
		*msgf &= ~(H2_MSGF_BODY|H2_MSGF_BODY_CL);
	else
		*msgf &= ~H2_MSGF_BODY_TUNNEL;

	if (!(*msgf & H2_MSGF_BODY) || ((*msgf & H2_MSGF_BODY_CL) && *body_len == 0) ||
	    (*msgf & H2_MSGF_BODY_TUNNEL)) {
		/* Response without body or tunnel successfully established */
		sl_flags |= HTX_SL_F_BODYLESS;
		htx->flags |= HTX_FL_EOM;
	}

	/* update the start line with last detected header info */
	sl->flags |= sl_flags;

	if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY) {
		/* FIXME: Do we need to signal anything when we have a body and
		 * no content-length, to have the equivalent of H1's chunked
		 * encoding?
		 */
	}

	/* now send the end of headers marker */
	if (!htx_add_endof(htx, HTX_BLK_EOH))
		goto fail;

	ret = 1;
	return ret;

 fail:
	return -1;
}


int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len)
{
	struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
	uint32_t fields; /* bit mask of H2_PHDR_FND_* */
	uint32_t idx;
	int ck, lck; /* cookie index and last cookie index */
	int phdr;
	int ret;
	int i;
	struct htx_sl *sl = NULL;
	unsigned int sl_flags = 0;
	const char *ctl;

	lck = ck = -1; // no cookie for now
	fields = 0;
	for (idx = 0; list[idx].n.len != 0; idx++) {
		if (!list[idx].n.ptr) {
			/* this is an indexed pseudo-header */
			phdr = list[idx].n.len;
		}
		else {
			/* this can be any type of header */
			/* RFC7540#8.1.2: upper case not allowed in header field names.
			 * #10.3: header names must be valid (i.e. match a token).
			 * For pseudo-headers we check from 2nd char and for other ones
			 * from the first char, because HTTP_IS_TOKEN() also excludes
			 * the colon.
			 */
			phdr = h2_str_to_phdr(list[idx].n);

			for (i = !!phdr; i < list[idx].n.len; i++)
				if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
					goto fail;
		}

		/* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
		 * rejecting NUL, CR and LF characters.
		 */
		ctl = ist_find_ctl(list[idx].v);
		if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
			goto fail;

		if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
			/* insert a pseudo header by its index (in phdr) and value (in value) */
			if (fields & ((1 << phdr) | H2_PHDR_FND_NONE)) {
				if (fields & H2_PHDR_FND_NONE) {
					/* pseudo header field after regular headers */
					goto fail;
				}
				else {
					/* repeated pseudo header field */
					goto fail;
				}
			}
			fields |= 1 << phdr;
			phdr_val[phdr] = list[idx].v;
			continue;
		}
		else if (phdr != 0) {
			/* invalid pseudo header -- should never happen here */
			goto fail;
		}

		/* regular header field in (name,value) */
		if (unlikely(!(fields & H2_PHDR_FND_NONE))) {
			/* no more pseudo-headers, time to build the request line */
			sl = h2_prepare_htx_reqline(fields, phdr_val, htx, msgf);
			if (!sl)
				goto fail;
			fields |= H2_PHDR_FND_NONE;

			/* http2bis draft recommends to drop Host in favor of :authority when
			 * the latter is present. This is required to make sure there is no
			 * discrepancy between the authority and the host header, especially
			 * since routing rules usually involve Host. Here we already know if
			 * :authority was found so we can emit it right now and mark the host
			 * as filled so that it's skipped later.
			 */
			if (fields & H2_PHDR_FND_AUTH) {
				if (!htx_add_header(htx, ist("host"), phdr_val[H2_PHDR_IDX_AUTH]))
					goto fail;
				fields |= H2_PHDR_FND_HOST;
			}
		}

		if (isteq(list[idx].n, ist("host"))) {
			if (fields & H2_PHDR_FND_HOST)
				continue;

			fields |= H2_PHDR_FND_HOST;
		}

		if (isteq(list[idx].n, ist("content-length"))) {
			ret = h2_parse_cont_len_header(msgf, &list[idx].v, body_len);
			if (ret < 0)
				goto fail;

			sl_flags |= HTX_SL_F_CLEN;
			if (ret == 0)
				continue; // skip this duplicate
		}

		/* these ones are forbidden in requests (RFC7540#8.1.2.2) */
		if (isteq(list[idx].n, ist("connection")) ||
		    isteq(list[idx].n, ist("proxy-connection")) ||
		    isteq(list[idx].n, ist("keep-alive")) ||
		    isteq(list[idx].n, ist("upgrade")) ||
		    isteq(list[idx].n, ist("transfer-encoding")))
			goto fail;

		if (isteq(list[idx].n, ist("te")) && !isteq(list[idx].v, ist("trailers")))
			goto fail;

		/* cookie requires special processing at the end */
		if (isteq(list[idx].n, ist("cookie"))) {
			list[idx].n.len = -1;

			if (ck < 0)
				ck = idx;
			else
				list[lck].n.len = idx;

			lck = idx;
			continue;
		}

		if (!htx_add_header(htx, list[idx].n, list[idx].v))
			goto fail;
	}

	/* RFC7540#8.1.2.1 mandates to reject response pseudo-headers (:status) */
	if (fields & H2_PHDR_FND_STAT)
		goto fail;

	/* Let's dump the request now if not yet emitted. */
	if (!(fields & H2_PHDR_FND_NONE)) {
		sl = h2_prepare_htx_reqline(fields, phdr_val, htx, msgf);
		if (!sl)
			goto fail;
	}

	if (*msgf & H2_MSGF_BODY_TUNNEL)
		*msgf &= ~(H2_MSGF_BODY|H2_MSGF_BODY_CL);

	if (!(*msgf & H2_MSGF_BODY) || ((*msgf & H2_MSGF_BODY_CL) && *body_len == 0) ||
	    (*msgf & H2_MSGF_BODY_TUNNEL)) {
		/* Request without body or tunnel requested */
		sl_flags |= HTX_SL_F_BODYLESS;
		htx->flags |= HTX_FL_EOM;
	}

	if (*msgf & H2_MSGF_EXT_CONNECT) {
		if (!htx_add_header(htx, ist("upgrade"), phdr_val[H2_PHDR_IDX_PROT]))
			goto fail;
		if (!htx_add_header(htx, ist("connection"), ist("upgrade")))
			goto fail;
		sl_flags |= HTX_SL_F_CONN_UPG;
	}

	/* update the start line with last detected header info */
	sl->flags |= sl_flags;

	/* complete with missing Host if needed (we may validate this test if
	 * no regular header was found).
	 */
	if ((fields & (H2_PHDR_FND_HOST|H2_PHDR_FND_AUTH)) == H2_PHDR_FND_AUTH) {
		/* missing Host field, use :authority instead */
		if (!htx_add_header(htx, ist("host"), phdr_val[H2_PHDR_IDX_AUTH]))
			goto fail;
	}

	/* now we may have to build a cookie list. We'll dump the values of all
	 * visited headers.
	 */
	if (ck >= 0) {
		uint32_t fs; // free space
		uint32_t bs; // block size
		uint32_t vl; // value len
		uint32_t tl; // total length
		struct htx_blk *blk;

		blk = htx_add_header(htx, ist("cookie"), list[ck].v);
		if (!blk)
			goto fail;

		tl = list[ck].v.len;
		fs = htx_free_data_space(htx);
		bs = htx_get_blksz(blk);

		/* for each extra cookie, we'll extend the cookie's value and
		 * insert "; " before the new value.
		 */
		fs += tl; // first one is already counted
		while ((ck = list[ck].n.len) >= 0) {
			vl = list[ck].v.len;
			tl += vl + 2;
			if (tl > fs)
				goto fail;

			htx_change_blk_value_len(htx, blk, tl);
			*(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';';
			*(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' ';
			memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl);
			bs += vl + 2;
		}

	}

	/* now send the end of headers marker */
	if (!htx_add_endof(htx, HTX_BLK_EOH))
		goto fail;

	/* proceed to scheme-based normalization on target-URI */
	if (fields & H2_PHDR_FND_SCHM)
		http_scheme_based_normalize(htx);

	ret = 1;
	return ret;

 fail:
	return -1;
}


static ssize_t enabled_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	bool mode = true;

	/* Default is enabled */
	if (dev->parent) {
		struct powercap_zone *power_zone = to_powercap_zone(dev);
		if (power_zone->ops->get_enable)
			if (power_zone->ops->get_enable(power_zone, &mode))
				mode = false;
	} else {
		struct powercap_control_type *control_type =
						to_powercap_control_type(dev);
		if (control_type->ops && control_type->ops->get_enable)
			if (control_type->ops->get_enable(control_type, &mode))
				mode = false;
	}

	return sprintf(buf, "%d\n", mode);
}

powercap: restrict energy meter to root access

Remove non-privileged user access to power data contained in
/sys/class/powercap/intel-rapl*/*/energy_uj

Non-privileged users currently have read access to power data and can
use this data to form a security attack. Some privileged
drivers/applications need read access to this data, but don't expose it
to non-privileged users.

For example, thermald uses this data to ensure that power management
works correctly. Thus removing non-privileged access is preferred over
completely disabling this power reporting capability with
CONFIG_INTEL_RAPL=n.

Fixes: 95677a9a3847 ("PowerCap: Fix mode for energy counter")

Signed-off-by: Len Brown <len.brown@intel.com>
Cc: stable@vger.kernel.org

#define to_powercap_zone(n) container_of(n, struct powercap_zone, dev)

#define to_powercap_control_type(n) \
			container_of(n, struct powercap_control_type, dev)

#define define_power_zone_show(_attr)		\
static ssize_t _attr##_show(struct device *dev, \
					struct device_attribute *dev_attr,\
					char *buf) \
{ \
	u64 value; \
	ssize_t len = -EINVAL; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	\
	if (power_zone->ops->get_##_attr) { \
		if (!power_zone->ops->get_##_attr(power_zone, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_store(_attr)		\
static ssize_t _attr##_store(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	u64 value; \
	\
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (value) \
		return count; \
	if (power_zone->ops->reset_##_attr) { \
		if (!power_zone->ops->reset_##_attr(power_zone)) \
			return count; \
	} \
	\
	return -EINVAL; \
}

#define define_power_zone_constraint_show(_attr) \
static ssize_t show_constraint_##_attr(struct device *dev, \
				struct device_attribute *dev_attr,\
				char *buf) \
{ \
	u64 value; \
	ssize_t len = -ENODATA; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
		if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_constraint_store(_attr) \
static ssize_t store_constraint_##_attr(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	u64 value; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
		if (!pconst->ops->set_##_attr(power_zone, id, value)) \
			return count; \
	} \
	\
	return -ENODATA; \
}

static DEVICE_ATTR_RO(max_power_range_uw);

static DEVICE_ATTR_RO(power_uw);

static DEVICE_ATTR_RO(max_energy_range_uj);

static DEVICE_ATTR_RW(energy_uj);


int powercap_unregister_zone(struct powercap_control_type *control_type,
				struct powercap_zone *power_zone)
{
	if (!power_zone || !control_type)
		return -EINVAL;

	mutex_lock(&control_type->lock);
	control_type->nr_zones--;
	mutex_unlock(&control_type->lock);

	device_unregister(&power_zone->dev);

	return 0;
}

#define to_powercap_zone(n) container_of(n, struct powercap_zone, dev)

#define to_powercap_control_type(n) \
			container_of(n, struct powercap_control_type, dev)

#define define_power_zone_show(_attr)		\
static ssize_t _attr##_show(struct device *dev, \
					struct device_attribute *dev_attr,\
					char *buf) \
{ \
	u64 value; \
	ssize_t len = -EINVAL; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	\
	if (power_zone->ops->get_##_attr) { \
		if (!power_zone->ops->get_##_attr(power_zone, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_store(_attr)		\
static ssize_t _attr##_store(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	u64 value; \
	\
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (value) \
		return count; \
	if (power_zone->ops->reset_##_attr) { \
		if (!power_zone->ops->reset_##_attr(power_zone)) \
			return count; \
	} \
	\
	return -EINVAL; \
}

#define define_power_zone_constraint_show(_attr) \
static ssize_t show_constraint_##_attr(struct device *dev, \
				struct device_attribute *dev_attr,\
				char *buf) \
{ \
	u64 value; \
	ssize_t len = -ENODATA; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
		if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_constraint_store(_attr) \
static ssize_t store_constraint_##_attr(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	u64 value; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
		if (!pconst->ops->set_##_attr(power_zone, id, value)) \
			return count; \
	} \
	\
	return -ENODATA; \
}


static ssize_t enabled_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf,  size_t len)
{
	bool mode;

	if (strtobool(buf, &mode))
		return -EINVAL;
	if (dev->parent) {
		struct powercap_zone *power_zone = to_powercap_zone(dev);
		if (power_zone->ops->set_enable)
			if (!power_zone->ops->set_enable(power_zone, mode))
				return len;
	} else {
		struct powercap_control_type *control_type =
						to_powercap_control_type(dev);
		if (control_type->ops && control_type->ops->set_enable)
			if (!control_type->ops->set_enable(control_type, mode))
				return len;
	}

	return -ENOSYS;
}


static int __init powercap_init(void)
{
	int result;

	result = seed_constraint_attributes();
	if (result)
		return result;

	return class_register(&powercap_class);
}

#define define_power_zone_show(_attr)		\
static ssize_t _attr##_show(struct device *dev, \
					struct device_attribute *dev_attr,\
					char *buf) \
{ \
	u64 value; \
	ssize_t len = -EINVAL; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	\
	if (power_zone->ops->get_##_attr) { \
		if (!power_zone->ops->get_##_attr(power_zone, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_store(_attr)		\
static ssize_t _attr##_store(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	u64 value; \
	\
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (value) \
		return count; \
	if (power_zone->ops->reset_##_attr) { \
		if (!power_zone->ops->reset_##_attr(power_zone)) \
			return count; \
	} \
	\
	return -EINVAL; \
}

#define define_power_zone_constraint_show(_attr) \
static ssize_t show_constraint_##_attr(struct device *dev, \
				struct device_attribute *dev_attr,\
				char *buf) \
{ \
	u64 value; \
	ssize_t len = -ENODATA; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
		if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_constraint_store(_attr) \
static ssize_t store_constraint_##_attr(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	u64 value; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
		if (!pconst->ops->set_##_attr(power_zone, id, value)) \
			return count; \
	} \
	\
	return -ENODATA; \
}

static DEVICE_ATTR_RO(max_power_range_uw);

static DEVICE_ATTR_RO(power_uw);

static DEVICE_ATTR_RO(max_energy_range_uj);

static DEVICE_ATTR_RW(energy_uj);

static struct powercap_constraint_attr
				constraint_attrs[MAX_CONSTRAINTS_PER_ZONE];

static LIST_HEAD(powercap_cntrl_list);

static DEFINE_MUTEX(powercap_cntrl_list_lock);

static DEVICE_ATTR_RO(name);


static void powercap_release(struct device *dev)
{
	bool allocated;

	if (dev->parent) {
		struct powercap_zone *power_zone = to_powercap_zone(dev);

		/* Store flag as the release() may free memory */
		allocated = power_zone->allocated;
		/* Remove id from parent idr struct */
		idr_remove(power_zone->parent_idr, power_zone->id);
		/* Destroy idrs allocated for this zone */
		idr_destroy(&power_zone->idr);
		kfree(power_zone->name);
		kfree(power_zone->zone_dev_attrs);
		kfree(power_zone->constraints);
		if (power_zone->ops->release)
			power_zone->ops->release(power_zone);
		if (allocated)
			kfree(power_zone);
	} else {
		struct powercap_control_type *control_type =
						to_powercap_control_type(dev);

		/* Store flag as the release() may free memory */
		allocated = control_type->allocated;
		idr_destroy(&control_type->idr);
		mutex_destroy(&control_type->lock);
		if (control_type->ops && control_type->ops->release)
			control_type->ops->release(control_type);
		if (allocated)
			kfree(control_type);
	}
}


int powercap_unregister_control_type(struct powercap_control_type *control_type)
{
	struct powercap_control_type *pos = NULL;

	if (control_type->nr_zones) {
		dev_err(&control_type->dev, "Zones of this type still not freed\n");
		return -EINVAL;
	}
	mutex_lock(&powercap_cntrl_list_lock);
	list_for_each_entry(pos, &powercap_cntrl_list, node) {
		if (pos == control_type) {
			list_del(&control_type->node);
			mutex_unlock(&powercap_cntrl_list_lock);
			device_unregister(&control_type->dev);
			return 0;
		}
	}
	mutex_unlock(&powercap_cntrl_list_lock);

	return -ENODEV;
}


static void create_power_zone_common_attributes(
					struct powercap_zone *power_zone)
{
	int count = 0;

	power_zone->zone_dev_attrs[count++] = &dev_attr_name.attr;
	if (power_zone->ops->get_max_energy_range_uj)
		power_zone->zone_dev_attrs[count++] =
					&dev_attr_max_energy_range_uj.attr;
	if (power_zone->ops->get_energy_uj) {
		if (power_zone->ops->reset_energy_uj)
			dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUSR;
		else
			dev_attr_energy_uj.attr.mode = S_IRUSR;
		power_zone->zone_dev_attrs[count++] =
					&dev_attr_energy_uj.attr;
	}
	if (power_zone->ops->get_power_uw)
		power_zone->zone_dev_attrs[count++] =
					&dev_attr_power_uw.attr;
	if (power_zone->ops->get_max_power_range_uw)
		power_zone->zone_dev_attrs[count++] =
					&dev_attr_max_power_range_uw.attr;
	power_zone->zone_dev_attrs[count] = NULL;
	power_zone->zone_attr_count = count;
}


struct powercap_control_type *powercap_register_control_type(
				struct powercap_control_type *control_type,
				const char *name,
				const struct powercap_control_type_ops *ops)
{
	int result;

	if (!name)
		return ERR_PTR(-EINVAL);
	if (control_type) {
		if (!ops || !ops->release)
			return ERR_PTR(-EINVAL);
		memset(control_type, 0, sizeof(*control_type));
	} else {
		control_type = kzalloc(sizeof(*control_type), GFP_KERNEL);
		if (!control_type)
			return ERR_PTR(-ENOMEM);
		control_type->allocated = true;
	}
	mutex_init(&control_type->lock);
	control_type->ops = ops;
	INIT_LIST_HEAD(&control_type->node);
	control_type->dev.class = &powercap_class;
	dev_set_name(&control_type->dev, "%s", name);
	result = device_register(&control_type->dev);
	if (result) {
		if (control_type->allocated)
			kfree(control_type);
		return ERR_PTR(result);
	}
	idr_init(&control_type->idr);

	mutex_lock(&powercap_cntrl_list_lock);
	list_add_tail(&control_type->node, &powercap_cntrl_list);
	mutex_unlock(&powercap_cntrl_list_lock);

	return control_type;
}


static int create_constraint_attribute(int id, const char *name,
				int mode,
				struct device_attribute *dev_attr,
				ssize_t (*show)(struct device *,
					struct device_attribute *, char *),
				ssize_t (*store)(struct device *,
					struct device_attribute *,
				const char *, size_t)
				)
{

	dev_attr->attr.name = kasprintf(GFP_KERNEL, "constraint_%d_%s",
								id, name);
	if (!dev_attr->attr.name)
		return -ENOMEM;
	dev_attr->attr.mode = mode;
	dev_attr->show = show;
	dev_attr->store = store;

	return 0;
}


static int create_constraints(struct powercap_zone *power_zone,
			int nr_constraints,
			const struct powercap_zone_constraint_ops *const_ops)
{
	int i;
	int ret = 0;
	int count;
	struct powercap_zone_constraint *pconst;

	if (!power_zone || !const_ops || !const_ops->get_power_limit_uw ||
					!const_ops->set_power_limit_uw ||
					!const_ops->get_time_window_us ||
					!const_ops->set_time_window_us)
		return -EINVAL;

	count = power_zone->zone_attr_count;
	for (i = 0; i < nr_constraints; ++i) {
		pconst = &power_zone->constraints[i];
		pconst->ops = const_ops;
		pconst->id = power_zone->const_id_cnt;
		power_zone->const_id_cnt++;
		power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].power_limit_attr.attr;
		power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].time_window_attr.attr;
		if (pconst->ops->get_name)
			power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].name_attr.attr;
		if (pconst->ops->get_max_power_uw)
			power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].max_power_attr.attr;
		if (pconst->ops->get_min_power_uw)
			power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].min_power_attr.attr;
		if (pconst->ops->get_max_time_window_us)
			power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].max_time_window_attr.attr;
		if (pconst->ops->get_min_time_window_us)
			power_zone->zone_dev_attrs[count++] =
				&constraint_attrs[i].min_time_window_attr.attr;
	}
	power_zone->zone_attr_count = count;

	return ret;
}


static int seed_constraint_attributes(void)
{
	int i;
	int ret;

	for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
		ret = create_constraint_attribute(i, "power_limit_uw",
					S_IWUSR | S_IRUGO,
					&constraint_attrs[i].power_limit_attr,
					show_constraint_power_limit_uw,
					store_constraint_power_limit_uw);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "time_window_us",
					S_IWUSR | S_IRUGO,
					&constraint_attrs[i].time_window_attr,
					show_constraint_time_window_us,
					store_constraint_time_window_us);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "name", S_IRUGO,
				&constraint_attrs[i].name_attr,
				show_constraint_name,
				NULL);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO,
				&constraint_attrs[i].max_power_attr,
				show_constraint_max_power_uw,
				NULL);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO,
				&constraint_attrs[i].min_power_attr,
				show_constraint_min_power_uw,
				NULL);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "max_time_window_us",
				S_IRUGO,
				&constraint_attrs[i].max_time_window_attr,
				show_constraint_max_time_window_us,
				NULL);
		if (ret)
			goto err_alloc;
		ret = create_constraint_attribute(i, "min_time_window_us",
				S_IRUGO,
				&constraint_attrs[i].min_time_window_attr,
				show_constraint_min_time_window_us,
				NULL);
		if (ret)
			goto err_alloc;

	}

	return 0;

err_alloc:
	free_constraint_attributes();

	return ret;
}

#define define_power_zone_show(_attr)		\
static ssize_t _attr##_show(struct device *dev, \
					struct device_attribute *dev_attr,\
					char *buf) \
{ \
	u64 value; \
	ssize_t len = -EINVAL; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	\
	if (power_zone->ops->get_##_attr) { \
		if (!power_zone->ops->get_##_attr(power_zone, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_store(_attr)		\
static ssize_t _attr##_store(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	u64 value; \
	\
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (value) \
		return count; \
	if (power_zone->ops->reset_##_attr) { \
		if (!power_zone->ops->reset_##_attr(power_zone)) \
			return count; \
	} \
	\
	return -EINVAL; \
}

#define define_power_zone_constraint_show(_attr) \
static ssize_t show_constraint_##_attr(struct device *dev, \
				struct device_attribute *dev_attr,\
				char *buf) \
{ \
	u64 value; \
	ssize_t len = -ENODATA; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
		if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
			len = sprintf(buf, "%lld\n", value); \
	} \
	\
	return len; \
}

#define define_power_zone_constraint_store(_attr) \
static ssize_t store_constraint_##_attr(struct device *dev,\
				struct device_attribute *dev_attr, \
				const char *buf, size_t count) \
{ \
	int err; \
	u64 value; \
	struct powercap_zone *power_zone = to_powercap_zone(dev); \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
	pconst = &power_zone->constraints[id]; \
	err = kstrtoull(buf, 10, &value); \
	if (err) \
		return -EINVAL; \
	if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
		if (!pconst->ops->set_##_attr(power_zone, id, value)) \
			return count; \
	} \
	\
	return -ENODATA; \
}

static DEVICE_ATTR_RO(max_power_range_uw);

static DEVICE_ATTR_RO(power_uw);

static DEVICE_ATTR_RO(max_energy_range_uj);

static DEVICE_ATTR_RW(energy_uj);


struct powercap_zone *powercap_register_zone(
			struct powercap_zone *power_zone,
			struct powercap_control_type *control_type,
			const char *name,
			struct powercap_zone *parent,
			const struct powercap_zone_ops *ops,
			int nr_constraints,
			const struct powercap_zone_constraint_ops *const_ops)
{
	int result;
	int nr_attrs;

	if (!name || !control_type || !ops ||
			nr_constraints > MAX_CONSTRAINTS_PER_ZONE ||
			(!ops->get_energy_uj && !ops->get_power_uw) ||
			!control_type_valid(control_type))
		return ERR_PTR(-EINVAL);

	if (power_zone) {
		if (!ops->release)
			return ERR_PTR(-EINVAL);
		memset(power_zone, 0, sizeof(*power_zone));
	} else {
		power_zone = kzalloc(sizeof(*power_zone), GFP_KERNEL);
		if (!power_zone)
			return ERR_PTR(-ENOMEM);
		power_zone->allocated = true;
	}
	power_zone->ops = ops;
	power_zone->control_type_inst = control_type;
	if (!parent) {
		power_zone->dev.parent = &control_type->dev;
		power_zone->parent_idr = &control_type->idr;
	} else {
		power_zone->dev.parent = &parent->dev;
		power_zone->parent_idr = &parent->idr;
	}
	power_zone->dev.class = &powercap_class;

	mutex_lock(&control_type->lock);
	/* Using idr to get the unique id */
	result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL);
	if (result < 0)
		goto err_idr_alloc;

	power_zone->id = result;
	idr_init(&power_zone->idr);
	result = -ENOMEM;
	power_zone->name = kstrdup(name, GFP_KERNEL);
	if (!power_zone->name)
		goto err_name_alloc;
	dev_set_name(&power_zone->dev, "%s:%x",
					dev_name(power_zone->dev.parent),
					power_zone->id);
	power_zone->constraints = kcalloc(nr_constraints,
					  sizeof(*power_zone->constraints),
					  GFP_KERNEL);
	if (!power_zone->constraints)
		goto err_const_alloc;

	nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS +
						POWERCAP_ZONE_MAX_ATTRS + 1;
	power_zone->zone_dev_attrs = kcalloc(nr_attrs, sizeof(void *),
					     GFP_KERNEL);
	if (!power_zone->zone_dev_attrs)
		goto err_attr_alloc;
	create_power_zone_common_attributes(power_zone);
	result = create_constraints(power_zone, nr_constraints, const_ops);
	if (result)
		goto err_dev_ret;

	power_zone->zone_dev_attrs[power_zone->zone_attr_count] = NULL;
	power_zone->dev_zone_attr_group.attrs = power_zone->zone_dev_attrs;
	power_zone->dev_attr_groups[0] = &power_zone->dev_zone_attr_group;
	power_zone->dev_attr_groups[1] = NULL;
	power_zone->dev.groups = power_zone->dev_attr_groups;
	result = device_register(&power_zone->dev);
	if (result)
		goto err_dev_ret;

	control_type->nr_zones++;
	mutex_unlock(&control_type->lock);

	return power_zone;

err_dev_ret:
	kfree(power_zone->zone_dev_attrs);
err_attr_alloc:
	kfree(power_zone->constraints);
err_const_alloc:
	kfree(power_zone->name);
err_name_alloc:
	idr_remove(power_zone->parent_idr, power_zone->id);
err_idr_alloc:
	if (power_zone->allocated)
		kfree(power_zone);
	mutex_unlock(&control_type->lock);

	return ERR_PTR(result);
}


static void free_constraint_attributes(void)
{
	int i;

	for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
		kfree(constraint_attrs[i].power_limit_attr.attr.name);
		kfree(constraint_attrs[i].time_window_attr.attr.name);
		kfree(constraint_attrs[i].name_attr.attr.name);
		kfree(constraint_attrs[i].max_power_attr.attr.name);
		kfree(constraint_attrs[i].min_power_attr.attr.name);
		kfree(constraint_attrs[i].max_time_window_attr.attr.name);
		kfree(constraint_attrs[i].min_time_window_attr.attr.name);
	}
}


static ssize_t show_constraint_name(struct device *dev,
				struct device_attribute *dev_attr,
				char *buf)
{
	const char *name;
	struct powercap_zone *power_zone = to_powercap_zone(dev);
	int id;
	ssize_t len = -ENODATA;
	struct powercap_zone_constraint *pconst;

	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id))
		return -EINVAL;
	if (id >= power_zone->const_id_cnt)
		return -EINVAL;
	pconst = &power_zone->constraints[id];

	if (pconst && pconst->ops && pconst->ops->get_name) {
		name = pconst->ops->get_name(power_zone, id);
		if (name) {
			snprintf(buf, POWERCAP_CONSTRAINT_NAME_LEN,
								"%s\n", name);
			buf[POWERCAP_CONSTRAINT_NAME_LEN] = '\0';
			len = strlen(buf);
		}
	}

	return len;
}


static ssize_t name_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	struct powercap_zone *power_zone = to_powercap_zone(dev);

	return sprintf(buf, "%s\n", power_zone->name);
}


static bool control_type_valid(void *control_type)
{
	struct powercap_control_type *pos = NULL;
	bool found = false;

	mutex_lock(&powercap_cntrl_list_lock);

	list_for_each_entry(pos, &powercap_cntrl_list, node) {
		if (pos == control_type) {
			found = true;
			break;
		}
	}
	mutex_unlock(&powercap_cntrl_list_lock);

	return found;
}


void my_reset_marker_reader(j_decompress_ptr dinfo)
{
}

tjDecompressToYUV*(): Fix OOB write/double free

... when attempting to decompress grayscale JPEG images with sampling
factors != 1.

Fixes #387

extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
	unsigned long *, boolean);

extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
	unsigned long);

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

DLLEXPORT void


static int setCompDefaults(struct jpeg_compress_struct *cinfo,
	int pixelFormat, int subsamp, int jpegQual, int flags)
{
	int retval=0;
#ifndef NO_GETENV
	char *env=NULL;
#endif

	switch(pixelFormat)
	{
		case TJPF_GRAY:
			cinfo->in_color_space=JCS_GRAYSCALE;  break;
		#if JCS_EXTENSIONS==1
		case TJPF_RGB:
			cinfo->in_color_space=JCS_EXT_RGB;  break;
		case TJPF_BGR:
			cinfo->in_color_space=JCS_EXT_BGR;  break;
		case TJPF_RGBX:
		case TJPF_RGBA:
			cinfo->in_color_space=JCS_EXT_RGBX;  break;
		case TJPF_BGRX:
		case TJPF_BGRA:
			cinfo->in_color_space=JCS_EXT_BGRX;  break;
		case TJPF_XRGB:
		case TJPF_ARGB:
			cinfo->in_color_space=JCS_EXT_XRGB;  break;
		case TJPF_XBGR:
		case TJPF_ABGR:
			cinfo->in_color_space=JCS_EXT_XBGR;  break;
		#else
		case TJPF_RGB:
		case TJPF_BGR:
		case TJPF_RGBX:
		case TJPF_BGRX:
		case TJPF_XRGB:
		case TJPF_XBGR:
		case TJPF_RGBA:
		case TJPF_BGRA:
		case TJPF_ARGB:
		case TJPF_ABGR:
			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
			break;
		#endif
		case TJPF_CMYK:
			cinfo->in_color_space=JCS_CMYK;  break;
	}

	cinfo->input_components=tjPixelSize[pixelFormat];
	jpeg_set_defaults(cinfo);

#ifndef NO_GETENV
	if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
		cinfo->optimize_coding=TRUE;
	if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
		cinfo->arith_code=TRUE;
	if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
	{
		int temp=-1;  char tempc=0;
		if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
		{
			if(toupper(tempc)=='B')
			{
				cinfo->restart_interval=temp;
				cinfo->restart_in_rows=0;
			}
			else
				cinfo->restart_in_rows=temp;
		}
	}
#endif

	if(jpegQual>=0)
	{
		jpeg_set_quality(cinfo, jpegQual, TRUE);
		if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
		else cinfo->dct_method=JDCT_FASTEST;
	}
	if(subsamp==TJSAMP_GRAY)
		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
	else if(pixelFormat==TJPF_CMYK)
		jpeg_set_colorspace(cinfo, JCS_YCCK);
	else jpeg_set_colorspace(cinfo, JCS_YCbCr);

#ifndef NO_GETENV
	if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
		&& !strcmp(env, "1"))
		jpeg_simple_progression(cinfo);
#endif

	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
	cinfo->comp_info[1].h_samp_factor=1;
	cinfo->comp_info[2].h_samp_factor=1;
	if(cinfo->num_components>3)
		cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
	cinfo->comp_info[1].v_samp_factor=1;
	cinfo->comp_info[2].v_samp_factor=1;
	if(cinfo->num_components>3)
		cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;

	return retval;
}

extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
	unsigned long *, boolean);

extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
	unsigned long);

static char errStr[JMSG_LENGTH_MAX]="No error";

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

typedef struct my_error_mgr *my_error_ptr;

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};

static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
{
	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
};

static const tjscalingfactor sf[NUMSF]={
	{2, 1},
	{15, 8},
	{7, 4},
	{13, 8},
	{3, 2},
	{11, 8},
	{5, 4},
	{9, 8},
	{1, 1},
	{7, 8},
	{3, 4},
	{5, 8},
	{1, 2},
	{3, 8},
	{1, 4},
	{1, 8}
};

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
	int rowPad=pitch-width*PS;  \
	while(height--)  \
	{  \
		unsigned char *endOfRow=src+width*PS;  \
		while(src<endOfRow)  \
		{  \
			dst[RGB_RED]=src[ROFFSET];  \
			dst[RGB_GREEN]=src[GOFFSET];  \
			dst[RGB_BLUE]=src[BOFFSET];  \
			dst+=RGB_PIXELSIZE;  src+=PS;  \
		}  \
		src+=rowPad;  \
	}  \
}


static int getPixelFormat(int pixelSize, int flags)
{
	if(pixelSize==1) return TJPF_GRAY;
	if(pixelSize==3)
	{
		if(flags&TJ_BGR) return TJPF_BGR;
		else return TJPF_RGB;
	}
	if(pixelSize==4)
	{
		if(flags&TJ_ALPHAFIRST)
		{
			if(flags&TJ_BGR) return TJPF_XBGR;
			else return TJPF_XRGB;
		}
		else
		{
			if(flags&TJ_BGR) return TJPF_BGRX;
			else return TJPF_RGBX;
		}
	}
	return -1;
}


DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
	int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
	int height, int pixelFormat, int flags)
{
	const unsigned char *srcPlanes[3];
	int pw0, ph0, strides[3], retval=-1;

	if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
		|| width<=0 || height<=0)
		_throw("tjDecodeYUV(): Invalid argument");

	pw0=tjPlaneWidth(0, width, subsamp);
	ph0=tjPlaneHeight(0, height, subsamp);
	srcPlanes[0]=srcBuf;
	strides[0]=PAD(pw0, pad);
	if(subsamp==TJSAMP_GRAY)
	{
		strides[1]=strides[2]=0;
		srcPlanes[1]=srcPlanes[2]=NULL;
	}
	else
	{
		int pw1=tjPlaneWidth(1, width, subsamp);
		int ph1=tjPlaneHeight(1, height, subsamp);
		strides[1]=strides[2]=PAD(pw1, pad);
		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
	}

	return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
		pitch, height, pixelFormat, flags);

	bailout:
	return retval;
}

extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
	unsigned long *, boolean);

extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
	unsigned long);

#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))

#define isPow2(x) (((x)&(x-1))==0)

static char errStr[JMSG_LENGTH_MAX]="No error";

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};

static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
{
	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
};

static const tjscalingfactor sf[NUMSF]={
	{2, 1},
	{15, 8},
	{7, 4},
	{13, 8},
	{3, 2},
	{11, 8},
	{5, 4},
	{9, 8},
	{1, 1},
	{7, 8},
	{3, 4},
	{5, 8},
	{1, 2},
	{3, 8},
	{1, 4},
	{1, 8}
};

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;


static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
	int pixelFormat, int flags)
{
	int retval=0;

	switch(pixelFormat)
	{
		case TJPF_GRAY:
			dinfo->out_color_space=JCS_GRAYSCALE;  break;
		#if JCS_EXTENSIONS==1
		case TJPF_RGB:
			dinfo->out_color_space=JCS_EXT_RGB;  break;
		case TJPF_BGR:
			dinfo->out_color_space=JCS_EXT_BGR;  break;
		case TJPF_RGBX:
			dinfo->out_color_space=JCS_EXT_RGBX;  break;
		case TJPF_BGRX:
			dinfo->out_color_space=JCS_EXT_BGRX;  break;
		case TJPF_XRGB:
			dinfo->out_color_space=JCS_EXT_XRGB;  break;
		case TJPF_XBGR:
			dinfo->out_color_space=JCS_EXT_XBGR;  break;
		#if JCS_ALPHA_EXTENSIONS==1
		case TJPF_RGBA:
			dinfo->out_color_space=JCS_EXT_RGBA;  break;
		case TJPF_BGRA:
			dinfo->out_color_space=JCS_EXT_BGRA;  break;
		case TJPF_ARGB:
			dinfo->out_color_space=JCS_EXT_ARGB;  break;
		case TJPF_ABGR:
			dinfo->out_color_space=JCS_EXT_ABGR;  break;
		#endif
		#else
		case TJPF_RGB:
		case TJPF_BGR:
		case TJPF_RGBX:
		case TJPF_BGRX:
		case TJPF_XRGB:
		case TJPF_XBGR:
		case TJPF_RGBA:
		case TJPF_BGRA:
		case TJPF_ARGB:
		case TJPF_ABGR:
			dinfo->out_color_space=JCS_RGB;  break;
		#endif
		case TJPF_CMYK:
			dinfo->out_color_space=JCS_CMYK;  break;
		default:
			_throw("Unsupported pixel format");
	}

	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;

	bailout:
	return retval;
}

static char errStr[JMSG_LENGTH_MAX]="No error";

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

typedef struct my_error_mgr *my_error_ptr;

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};

static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
{
	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
};

static const tjscalingfactor sf[NUMSF]={
	{2, 1},
	{15, 8},
	{7, 4},
	{13, 8},
	{3, 2},
	{11, 8},
	{5, 4},
	{9, 8},
	{1, 1},
	{7, 8},
	{3, 4},
	{5, 8},
	{1, 2},
	{3, 8},
	{1, 4},
	{1, 8}
};

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
	int rowPad=pitch-width*PS;  \
	while(height--)  \
	{  \
		unsigned char *endOfRow=src+width*PS;  \
		while(src<endOfRow)  \
		{  \
			dst[RGB_RED]=src[ROFFSET];  \
			dst[RGB_GREEN]=src[GOFFSET];  \
			dst[RGB_BLUE]=src[BOFFSET];  \
			dst+=RGB_PIXELSIZE;  src+=PS;  \
		}  \
		src+=rowPad;  \
	}  \
}


DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
	int jpegSubsamp)
{
	unsigned long retval=0;  int mcuw, mcuh, chromasf;
	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
		_throw("tjBufSize(): Invalid argument");

	/* This allows for rare corner cases in which a JPEG image can actually be
	   larger than the uncompressed input (we wouldn't mention it if it hadn't
	   happened before.) */
	mcuw=tjMCUWidth[jpegSubsamp];
	mcuh=tjMCUHeight[jpegSubsamp];
	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;

	bailout:
	return retval;
}

extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
	unsigned long *, boolean);

extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
	unsigned long);

#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
	int rowPad=pitch-width*PS;  \
	while(height--)  \
	{  \
		unsigned char *endOfRow=src+width*PS;  \
		while(src<endOfRow)  \
		{  \
			dst[RGB_RED]=src[ROFFSET];  \
			dst[RGB_GREEN]=src[GOFFSET];  \
			dst[RGB_BLUE]=src[BOFFSET];  \
			dst+=RGB_PIXELSIZE;  src+=PS;  \
		}  \
		src+=rowPad;  \
	}  \
}

#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
	int rowPad=pitch-width*PS;  \
	while(height--)  \
	{  \
		unsigned char *endOfRow=dst+width*PS;  \
		while(dst<endOfRow)  \
		{  \
			dst[ROFFSET]=src[RGB_RED];  \
			dst[GOFFSET]=src[RGB_GREEN];  \
			dst[BOFFSET]=src[RGB_BLUE];  \
			SETALPHA  \
			dst+=PS;  src+=RGB_PIXELSIZE;  \
		}  \
		dst+=rowPad;  \
	}  \
}

DLLEXPORT int

DLLEXPORT void

DLLEXPORT tjhandle

DLLEXPORT tjscalingfactor


DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
	const unsigned char *jpegBuf, unsigned long jpegSize, int n,
	unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
{
	jpeg_transform_info *xinfo=NULL;
	jvirt_barray_ptr *srccoefs, *dstcoefs;
	int retval=0, i, jpegSubsamp;

	getinstance(handle);
	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
		_throw("tjTransform(): Instance has not been initialized for transformation");

	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
		|| t==NULL || flags<0)
		_throw("tjTransform(): Invalid argument");

#ifndef NO_PUTENV
	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
#endif

	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
		==NULL)
		_throw("tjTransform(): Memory allocation failure");
	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);

	if(setjmp(this->jerr.setjmp_buffer))
	{
		/* If we get here, the JPEG code has signaled an error. */
		retval=-1;  goto bailout;
	}

	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);

	for(i=0; i<n; i++)
	{
		xinfo[i].transform=xformtypes[t[i].op];
		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
		else xinfo[i].slow_hflip=0;

		if(xinfo[i].crop)
		{
			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
			if(t[i].r.w!=0)
			{
				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
			}
			else xinfo[i].crop_width=JCROP_UNSET;
			if(t[i].r.h!=0)
			{
				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
			}
			else xinfo[i].crop_height=JCROP_UNSET;
		}
	}

	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
	jpeg_read_header(dinfo, TRUE);
	jpegSubsamp=getSubsamp(dinfo);
	if(jpegSubsamp<0)
		_throw("tjTransform(): Could not determine subsampling type for JPEG image");

	for(i=0; i<n; i++)
	{
		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
			_throw("tjTransform(): Transform is not perfect");

		if(xinfo[i].crop)
		{
			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
			{
				snprintf(errStr, JMSG_LENGTH_MAX,
					"To crop this JPEG image, x must be a multiple of %d\n"
					"and y must be a multiple of %d.\n",
					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
				retval=-1;  goto bailout;
			}
		}
	}

	srccoefs=jpeg_read_coefficients(dinfo);

	for(i=0; i<n; i++)
	{
		int w, h, alloc=1;
		if(!xinfo[i].crop)
		{
			w=dinfo->image_width;  h=dinfo->image_height;
		}
		else
		{
			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
		}
		if(flags&TJFLAG_NOREALLOC)
		{
			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
		}
		if(!(t[i].options&TJXOPT_NOOUTPUT))
			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
		jpeg_copy_critical_parameters(dinfo, cinfo);
		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
			&xinfo[i]);
		if(!(t[i].options&TJXOPT_NOOUTPUT))
		{
			jpeg_write_coefficients(cinfo, dstcoefs);
			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
		}
		else jinit_c_master_control(cinfo, TRUE);
		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
			&xinfo[i]);
		if(t[i].customFilter)
		{
			int ci, y;  JDIMENSION by;
			for(ci=0; ci<cinfo->num_components; ci++)
			{
				jpeg_component_info *compptr=&cinfo->comp_info[ci];
				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
					DCTSIZE};
				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
					compptr->height_in_blocks*DCTSIZE};
				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
				{
					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
						TRUE);
					for(y=0; y<compptr->v_samp_factor; y++)
					{
						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
							ci, i, &t[i])==-1)
							_throw("tjTransform(): Error in custom filter");
						arrayRegion.y+=DCTSIZE;
					}
				}
			}
		}
		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
	}

	jpeg_finish_decompress(dinfo);

	bailout:
	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
	if(xinfo) free(xinfo);
	if(this->jerr.warning) retval=-1;
	return retval;
}

extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
	unsigned long *, boolean);

extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
	unsigned long);

static char errStr[JMSG_LENGTH_MAX]="No error";

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
	void (*emit_message)(j_common_ptr, int);
	boolean warning;
}

enum {COMPRESS=1, DECOMPRESS=2}

typedef struct _tjinstance
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	int init, headerRead;
} tjinstance;

static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};

static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
{
	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
};

static const tjscalingfactor sf[NUMSF]={
	{2, 1},
	{15, 8},
	{7, 4},
	{13, 8},
	{3, 2},
	{11, 8},
	{5, 4},
	{9, 8},
	{1, 1},
	{7, 8},
	{3, 4},
	{5, 8},
	{1, 2},
	{3, 8},
	{1, 4},
	{1, 8}
};

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}

#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_compress_ptr cinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	cinfo=&this->cinfo;  \
	this->jerr.warning=FALSE;

#define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
	j_decompress_ptr dinfo=NULL;  \
	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
		return -1;}  \
	dinfo=&this->dinfo;  \
	this->jerr.warning=FALSE;

#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
	int rowPad=pitch-width*PS;  \
	while(height--)  \
	{  \
		unsigned char *endOfRow=src+width*PS;  \
		while(src<endOfRow)  \
		{  \
			dst[RGB_RED]=src[ROFFSET];  \
			dst[RGB_GREEN]=src[GOFFSET];  \
			dst[RGB_BLUE]=src[BOFFSET];  \
			dst+=RGB_PIXELSIZE;  src+=PS;  \
		}  \
		src+=rowPad;  \
	}  \
}