/* Copyright 2015 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE.chromium file. * * Converted to C89 2015 by Tim Rühsen */ #include #if defined(__GNUC__) && defined(__GNUC_MINOR__) # define _GCC_VERSION_AT_LEAST(major, minor) ((__GNUC__ > (major)) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) #else # define _GCC_VERSION_AT_LEAST(major, minor) 0 #endif #if _GCC_VERSION_AT_LEAST(4,0) # define _HIDDEN __attribute__ ((visibility ("hidden"))) #else # define _HIDDEN #endif #define CHECK_LT(a, b) if ((a) >= b) return 0 /* * Read next offset from pos. * Returns true if an offset could be read, false otherwise. */ static int GetNextOffset(const unsigned char** pos, const unsigned char* end, const unsigned char** offset) { size_t bytes_consumed; if (*pos == end) return 0; /* When reading an offset the byte array must always contain at least * three more bytes to consume. First the offset to read, then a node * to skip over and finally a destination node. No object can be smaller * than one byte. */ CHECK_LT(*pos + 2, end); switch (**pos & 0x60) { case 0x60: /* Read three byte offset */ *offset += (((*pos)[0] & 0x1F) << 16) | ((*pos)[1] << 8) | (*pos)[2]; bytes_consumed = 3; break; case 0x40: /* Read two byte offset */ *offset += (((*pos)[0] & 0x1F) << 8) | (*pos)[1]; bytes_consumed = 2; break; default: *offset += (*pos)[0] & 0x3F; bytes_consumed = 1; } if ((**pos & 0x80) != 0) { *pos = end; } else { *pos += bytes_consumed; } return 1; } /* * Check if byte at offset is last in label. */ static int IsEOL(const unsigned char* offset, const unsigned char* end) { CHECK_LT(offset, end); return(*offset & 0x80) != 0; } /* * Check if byte at offset matches first character in key. * This version matches characters not last in label. */ static int IsMatch(const unsigned char* offset, const unsigned char* end, const char* key) { CHECK_LT(offset, end); return *offset == *key; } /* * Check if byte at offset matches first character in key. * This version matches characters last in label. */ static int IsEndCharMatch(const unsigned char* offset, const unsigned char* end, const char* key) { CHECK_LT(offset, end); return *offset == (*key | 0x80); } /* * Read return value at offset. * Returns true if a return value could be read, false otherwise. */ static int GetReturnValue(const unsigned char* offset, const unsigned char* end, int* return_value) { CHECK_LT(offset, end); if ((*offset & 0xE0) == 0x80) { *return_value = *offset & 0x0F; return 1; } return 0; } /* * Looks up the string |key| with length |key_length| in a fixed set of * strings. The set of strings must be known at compile time. It is converted to * a graph structure named a DAFSA (Deterministic Acyclic Finite State * Automaton) by the script make_dafsa.py during compilation. This permits * efficient (in time and space) lookup. The graph generated by make_dafsa.py * takes the form of a constant byte array which should be supplied via the * |graph| and |length| parameters. The return value is kDafsaNotFound, * kDafsaFound, or a bitmap consisting of one or more of kDafsaExceptionRule, * kDafsaWildcardRule and kDafsaPrivateRule ORed together. * * Lookup a domain key in a byte array generated by make_dafsa.py. */ /* prototype to skip warning with -Wmissing-prototypes */ int _HIDDEN LookupStringInFixedSet(const unsigned char*, size_t,const char*, size_t); int _HIDDEN LookupStringInFixedSet(const unsigned char* graph, size_t length, const char* key, size_t key_length) { const unsigned char* pos = graph; const unsigned char* end = graph + length; const unsigned char* offset = pos; const char* key_end = key + key_length; while (GetNextOffset(&pos, end, &offset)) { /*char + end_char offsets * char + return value * char end_char offsets * char return value * end_char offsets * return_value */ int did_consume = 0; if (key != key_end && !IsEOL(offset, end)) { /* Leading is not a match. Don't dive into this child */ if (!IsMatch(offset, end, key)) continue; did_consume = 1; ++offset; ++key; /* Possible matches at this point: * + end_char offsets * + return value * end_char offsets * return value */ /* Remove all remaining nodes possible */ while (!IsEOL(offset, end) && key != key_end) { if (!IsMatch(offset, end, key)) return -1; ++key; ++offset; } } /* Possible matches at this point: * end_char offsets * return_value * If one or more elements were consumed, a failure * to match is terminal. Otherwise, try the next node. */ if (key == key_end) { int return_value; if (GetReturnValue(offset, end, &return_value)) return return_value; /* The DAFSA guarantees that if the first char is a match, all * remaining char elements MUST match if the key is truly present. */ if (did_consume) return -1; continue; } if (!IsEndCharMatch(offset, end, key)) { if (did_consume) return -1; /* Unexpected */ continue; } ++key; pos = ++offset; /* Dive into child */ } return -1; /* No match */ }