From 40cbd4625ae7f9799238594faa4f8cc54ead72e4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 3 Sep 2005 22:58:04 +0000 Subject: r10015: Change the NT4 registry backend to use the IDL-generate parse functions. (This used to be commit 0ad46ef804c0654e927f9c14ea93c45f9e3c718c) --- source4/include/registry.h | 9 - source4/lib/registry/config.mk | 10 + source4/lib/registry/reg_backend_nt4.c | 1815 ++++---------------------------- source4/lib/registry/regf.idl | 61 +- source4/pidl/lib/Parse/Pidl/IDL.pm | 1387 +++++++++++++----------- 5 files changed, 1042 insertions(+), 2240 deletions(-) (limited to 'source4') diff --git a/source4/include/registry.h b/source4/include/registry.h index dc17eb06b1..06442514f0 100644 --- a/source4/include/registry.h +++ b/source4/include/registry.h @@ -35,15 +35,6 @@ #define REG_DELETE -1 -#if 0 -/* FIXME */ -typedef struct ace_struct_s { - uint8_t type, flags; - uint_t perms; /* Perhaps a better def is in order */ - DOM_SID *trustee; -} ACE; -#endif - /* * The general idea here is that every backend provides a 'hive'. Combining * various hives gives you a complete registry like windows has diff --git a/source4/lib/registry/config.mk b/source4/lib/registry/config.mk index c533e17ea9..a1bb62f7df 100644 --- a/source4/lib/registry/config.mk +++ b/source4/lib/registry/config.mk @@ -7,9 +7,19 @@ INIT_FUNCTION = registry_nt4_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ lib/registry/reg_backend_nt4.o +REQUIRED_SUBSYSTEMS = TDR_REGF # End MODULE registry_nt4 ################################################ +[SUBSYSTEM::TDR_REGF] +REQUIRED_SUBSYSTEMS = TDR +NOPROTO = YES +INIT_OBJ_FILES = lib/registry/tdr_regf.o + +lib/registry/tdr_regf.c: lib/registry/regf.idl + @echo "Compiling lib/registry/regf.idl" + @./pidl/pidl --header --outputdir=lib/registry --parse --tdr-header --tdr-parser -- lib/registry/regf.idl + ################################################ # Start MODULE registry_w95 [MODULE::registry_w95] diff --git a/source4/lib/registry/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4.c index 06c0d78c85..e0f5ccd08c 100644 --- a/source4/lib/registry/reg_backend_nt4.c +++ b/source4/lib/registry/reg_backend_nt4.c @@ -1,7 +1,7 @@ /* - Samba Unix/Linux SMB client utility libeditreg.c - Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com - Copyright (C) 2003-2005 Jelmer Vernooij, jelmer@samba.org + Samba CIFS implementation + Registry backend for REGF files + Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,1720 +17,331 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/************************************************************************* - - A utility to edit a Windows NT/2K etc registry file. - - Many of the ideas in here come from other people and software. - I first looked in Wine in misc/registry.c and was also influenced by - http://www.wednesday.demon.co.uk/dosreg.html - - Which seems to contain comments from someone else. I reproduce them here - incase the site above disappears. It actually comes from - http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. - - The goal here is to read the registry into memory, manipulate it, and then - write it out if it was changed by any actions of the user. - -The windows NT registry has 2 different blocks, where one can occur many -times... - -the "regf"-Block -================ - -"regf" is obviously the abbreviation for "Registry file". "regf" is the -signature of the header-block which is always 4kb in size, although only -the first 64 bytes seem to be used and a checksum is calculated over -the first 0x200 bytes only! - -Offset Size Contents -0x00000000 D-Word ID: ASCII-"regf" = 0x66676572 -0x00000004 D-Word ???? //see struct REG_HANDLE -0x00000008 D-Word ???? Always the same value as at 0x00000004 -0x0000000C Q-Word last modify date in WinNT date-format -0x00000014 D-Word 1 -0x00000018 D-Word 3 -0x0000001C D-Word 0 -0x00000020 D-Word 1 -0x00000024 D-Word Offset of 1st key record -0x00000028 D-Word Size of the data-blocks (Filesize-4kb) -0x0000002C D-Word 1 -0x000001FC D-Word Sum of all D-Words from 0x00000000 to -0x000001FB //XOR of all words. Nigel - -I have analyzed more registry files (from multiple machines running -NT 4.0 german version) and could not find an explanation for the values -marked with ???? the rest of the first 4kb page is not important... - -the "hbin"-Block -================ -hbin probably means hive-bin (what bin stands for I don't know) -This block is always a multiple -of 4kb in size. - -Inside these hbin-blocks the different records are placed. The memory- -management looks like a C-compiler heap management to me... - -hbin-Header -=========== -Offset Size Contents -0x0000 D-Word ID: ASCII-"hbin" = 0x6E696268 -0x0004 D-Word Offset from the 1st hbin-Block -0x0008 D-Word Offset to the next hbin-Block -0x001C D-Word Block-size - -The values in 0x0008 and 0x001C should be the same, so I don't know -if they are correct or swapped... - -From offset 0x0020 inside a hbin-block data is stored with the following -format: - -Offset Size Contents -0x0000 D-Word Data-block size //this size must be a -multiple of 8. Nigel -0x0004 ???? Data - -If the size field is negative (bit 31 set), the corresponding block -is free and has a size of -blocksize! - -That does not seem to be true. All block lengths seem to be negative! -(Richard Sharpe) - -The data is stored as one record per block. Block size is a multiple -of 4 and the last block reaches the next hbin-block, leaving no room. - -(That also seems incorrect, in that the block size if a multiple of 8. -That is, the block, including the 4 byte header, is always a multiple of -8 bytes. Richard Sharpe.) - -Records in the hbin-blocks -========================== - -nk-Record - - The nk-record can be treated as a combination of tree-record and - key-record of the win 95 registry. - -lf-Record - - The lf-record is the counterpart to the RGKN-record (the - hash-function) - -vk-Record - - The vk-record consists information to a single value (value key). - -sk-Record - - sk (? Security Key ?) is the ACL of the registry. - -Value-Lists - - The value-lists contain information about which values are inside a - sub-key and don't have a header. - -Datas - - The datas of the registry are (like the value-list) stored without a - header. - -All offset-values are relative to the first hbin-block and point to the -block-size field of the record-entry. to get the file offset, you have to add -the header size (4kb) and the size field (4 bytes)... - -the nk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"nk" = 0x6B6E -0x0002 Word for the root-key: 0x2C, otherwise 0x20 //key symbolic links 0x10. Nigel -0x0004 Q-Word write-date/time in windows nt notation -0x0010 D-Word Offset of Owner/Parent key -0x0014 D-Word number of sub-Keys -0x001C D-Word Offset of the sub-key lf-Records -0x0024 D-Word number of values -0x0028 D-Word Offset of the Value-List -0x002C D-Word Offset of the sk-Record - -0x0030 D-Word Offset of the Class-Name //see NK structure for the use of these fields. Nigel -0x0044 D-Word Unused (data-trash) //some kind of run time index. Does not appear to be important. Nigel -0x0048 Word name-length -0x004A Word class-name length -0x004C ???? key-name - -the Value-List -============== -Offset Size Contents -0x0000 D-Word Offset 1st Value -0x0004 D-Word Offset 2nd Value -0x???? D-Word Offset nth Value - -To determine the number of values, you have to look at the owner-nk-record! - -The vk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"vk" = 0x6B76 -0x0002 Word name length -0x0004 D-Word length of the data //if top bit is set when offset contains data. Nigel -0x0008 D-Word Offset of Data -0x000C D-Word Type of value -0x0010 Word Flag -0x0012 Word Unused (data-trash) -0x0014 ???? Name - -If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default) - -If the data-size is lower 5, the data-offset value is used to store the data itself! - -The data-types -============== -Wert Beteutung -0x0001 RegSZ: character string (in UNICODE!) -0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!) -0x0003 RegBin: raw-binary value -0x0004 RegDWord: Dword -0x0007 RegMultiSZ: multiple strings, seperated with 0 - (UNICODE!) - -The "lf"-record -=============== -Offset Size Contents -0x0000 Word ID: ASCII-"lf" = 0x666C -0x0002 Word number of keys -0x0004 ???? Hash-Records - -Hash-Record -=========== -Offset Size Contents -0x0000 D-Word Offset of corresponding "nk"-Record -0x0004 D-Word ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv! - -Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the -key-name you have to change the hash-value too! - -//These hashrecords must be sorted low to high within the lf record. Nigel. - -The "sk"-block -============== -(due to the complexity of the SAM-info, not clear jet) -(This is just a self-relative security descriptor in the data. R Sharpe.) - - -Offset Size Contents -0x0000 Word ID: ASCII-"sk" = 0x6B73 -0x0002 Word Unused -0x0004 D-Word Offset of previous "sk"-Record -0x0008 D-Word Offset of next "sk"-Record -0x000C D-Word usage-counter -0x0010 D-Word Size of "sk"-record in bytes -???? //standard self -relative security desciptor. Nigel -???? ???? Security and auditing settings... -???? - -The usage counter counts the number of references to this -"sk"-record. You can use one "sk"-record for the entire registry! - -Windows nt date/time format -=========================== -The time-format is a 64-bit integer which is incremented every -0,0000001 seconds by 1 (I don't know how accurate it realy is!) -It starts with 0 at the 1st of january 1601 0:00! All values are -stored in GMT time! The time-zone is important to get the real -time! - -Common values for win95 and win-nt -================================== -Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF). -If a value has no name (length=0, flag(bit 0)=0), it is treated as the -"Default" entry... -If a value has no data (length=0), it is displayed as empty. - -simplyfied win-3.?? registry: -============================= - -+-----------+ -| next rec. |---+ +----->+------------+ -| first sub | | | | Usage cnt. | -| name | | +-->+------------+ | | length | -| value | | | | next rec. | | | text |------->+-------+ -+-----------+ | | | name rec. |--+ +------------+ | xxxxx | - +------------+ | | value rec. |-------->+------------+ +-------+ - v | +------------+ | Usage cnt. | -+-----------+ | | length | -| next rec. | | | text |------->+-------+ -| first sub |------+ +------------+ | xxxxx | -| name | +-------+ -| value | -+-----------+ - -Greatly simplyfied structure of the nt-registry: -================================================ - -+---------------------------------------------------------------+ -| | -v | -+---------+ +---------->+-----------+ +----->+---------+ | -| "nk" | | | lf-rec. | | | nk-rec. | | -| ID | | | # of keys | | | parent |---+ -| Date | | | 1st key |--+ | .... | -| parent | | +-----------+ +---------+ -| suk-keys|-----+ -| values |--------------------->+----------+ -| SK-rec. |---------------+ | 1. value |--> +----------+ -| class |--+ | +----------+ | vk-rec. | -+---------+ | | | .... | - v | | data |--> +-------+ - +------------+ | +----------+ | xxxxx | - | Class name | | +-------+ - +------------+ | - v - +---------+ +---------+ - +----->| next sk |--->| Next sk |--+ - | +---| prev sk |<---| prev sk | | - | | | .... | | ... | | - | | +---------+ +---------+ | - | | ^ | - | | | | - | +--------------------+ | - +----------------------------------+ - ---------------------------------------------------------------------------- - -Hope this helps.... (Although it was "fun" for me to uncover this things, - it took me several sleepless nights ;) - - B.D. - -*************************************************************************/ - #include "includes.h" #include "registry.h" #include "system/filesys.h" -#include "system/shmem.h" - -#define REG_KEY_LIST_SIZE 10 -#define FLAG_HAS_NAME 0x01 -/*FIXME*/ +#include "lib/registry/tdr_regf.h" /* - * Structures for dealing with the on-disk format of the registry + * Read HBIN blocks into memory */ -const char *def_owner_sid_str = NULL; - -/* - * These definitions are for the in-memory registry structure. - * It is a tree structure that mimics what you see with tools like regedit - */ - - -/* - * Definition of a Key. It has a name, classname, date/time last modified, - * sub-keys, values, and a security descriptor - */ - -#define REG_ROOT_KEY 1 -#define REG_SUB_KEY 2 -#define REG_SYM_LINK 3 - -/* - * All of the structures below actually have a four-byte length before them - * which always seems to be negative. The following macro retrieves that - * size as an integer - */ - -#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1)) - -typedef struct sk_struct SK_HDR; -/* - * This structure keeps track of the output format of the registry - */ -#define REG_OUTBLK_HDR 1 -#define REG_OUTBLK_HBIN 2 - -typedef struct regf_block { - uint32_t REGF_ID; /* regf */ - uint32_t update_counter1; - uint32_t update_counter2; - uint32_t tim1, tim2; - uint32_t uk3; /* 1 */ - uint32_t uk4; /* 3 */ - uint32_t uk5; /* 0 */ - uint32_t uk6; /* 1 */ - uint32_t first_key; /* offset */ - uint32_t dblk_size; - uint32_t uk7; /* 1 */ - wchar_t filename[64]; - uint32_t unused[83]; - uint32_t chksum; /* Checksum of first 0x200 bytes */ -} REGF_HDR; - -typedef struct hbin_sub_struct { - uint32_t dblocksize; - char data[1]; -} HBIN_SUB_HDR; - -typedef struct hbin_struct { - uint32_t HBIN_ID; /* hbin */ - uint32_t off_from_first; - uint32_t off_to_next; - uint32_t uk1; - uint32_t uk2; - uint32_t uk3; - uint32_t uk4; - uint32_t blk_size; - HBIN_SUB_HDR hbin_sub_hdr; -} HBIN_HDR; - -typedef struct nk_struct { - uint16_t NK_ID; - uint16_t type; - uint32_t t1, t2; - uint32_t uk1; - uint32_t own_off; - uint32_t subk_num; - uint32_t uk2; - uint32_t lf_off; - uint32_t uk3; - uint32_t val_cnt; - uint32_t val_off; - uint32_t sk_off; - uint32_t clsnam_off; - uint32_t unk4[4]; - uint32_t unk5; - uint16_t nam_len; - uint16_t clsnam_len; - char key_nam[1]; /* Actual length determined by nam_len */ -} NK_HDR; - -struct sk_struct { - uint16_t SK_ID; - uint16_t uk1; - uint32_t prev_off; - uint32_t next_off; - uint32_t ref_cnt; - uint32_t rec_size; - char sec_desc[1]; +struct regf_data { + DATA_BLOB data; + struct hbin_block **hbins; }; -typedef struct key_sec_desc_s { - struct key_sec_desc_s *prev, *next; - int ref_cnt; - int state; - int offset; - SK_HDR *sk_hdr; /* This means we must keep the registry in memory */ - struct security_descriptor *sec_desc; -} KEY_SEC_DESC; - -/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */ -typedef struct sk_map_s { - int sk_off; - KEY_SEC_DESC *key_sec_desc; -} SK_MAP; - -typedef struct vk_struct { - uint16_t VK_ID; - uint16_t nam_len; - uint32_t dat_len; /* If top-bit set, offset contains the data */ - uint32_t dat_off; - uint32_t dat_type; - uint16_t flag; /* =1, has name, else no name (=Default). */ - uint16_t unk1; - char dat_name[1]; /* Name starts here ... */ -} VK_HDR; - -typedef uint32_t VL_TYPE[1]; /* Value list is an array of vk rec offsets */ - -typedef struct hash_struct { - uint32_t nk_off; - char hash[4]; -} HASH_REC; - - -typedef struct lf_struct { - uint16_t LF_ID; - uint16_t key_count; - struct hash_struct hr[1]; /* Array of hash records, depending on key_count */} LF_HDR; - - - /* - * This structure keeps track of the output format of the registry + * Validate a regf header + * For now, do nothing, but we should check the checksum */ -#define REG_OUTBLK_HDR 1 -#define REG_OUTBLK_HBIN 2 - -typedef struct hbin_blk_s { - int type, size; - struct hbin_blk_s *next; - char *data; /* The data block */ - uint_t file_offset; /* Offset in file */ - uint_t free_space; /* Amount of free space in block */ - uint_t fsp_off; /* Start of free space in block */ - int complete, stored; -} HBIN_BLK; - -typedef struct regf_struct_s { - int reg_type; - int fd; - struct stat sbuf; - char *base; - BOOL modified; - NTTIME last_mod_time; - NK_HDR *first_key; - int sk_count, sk_map_size; - SK_MAP *sk_map; - const char *owner_sid_str; - struct security_descriptor *def_sec_desc; - /* - * These next pointers point to the blocks used to contain the - * keys when we are preparing to write them to a file - */ - HBIN_BLK *blk_head, *blk_tail, *free_space; -} REGF; - -static uint32_t str_to_dword(const char *a) { +static uint32_t regf_hdr_checksum(const uint8_t *buffer) +{ + uint32_t checksum = 0, x; int i; - unsigned long ret = 0; - for(i = strlen(a)-1; i >= 0; i--) { - ret = ret * 0x100 + a[i]; + + for (i = 0; i < 0x01FB; i+= 4) { + x = IVAL(buffer, i); + checksum ^= x; } - return ret; -} - -#if 0 -/* - * Create an ACE - */ -static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32_t perms, const char *sid) -{ - DOM_SID s; - SEC_ACCESS access; - access.mask = perms; - if(!string_to_sid(&s, sid))return False; - init_sec_ace(ace, &s, type, access, flags); - return True; + return checksum; } -/* - * Create a default ACL - */ -static SEC_ACL *nt_create_default_acl(struct registry_hive *regf) -{ - SEC_ACE aces[8]; - - if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL; - if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL; - if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL; - if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL; - if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL; - if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL; - if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL; - if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL; - - return make_sec_acl(regf->mem_ctx, 2, 8, aces); -} - -/* - * Create a default security descriptor. We pull in things from env - * if need be - */ -static SEC_DESC *nt_create_def_sec_desc(struct registry_hive *regf) -{ - SEC_DESC *tmp; - - tmp = malloc_p(SEC_DESC); - - tmp->revision = 1; - tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT; - if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error; - if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error; - tmp->sacl = NULL; - tmp->dacl = nt_create_default_acl(regf); - - return tmp; - - error: - if (tmp) nt_delete_sec_desc(tmp); - return NULL; -} - -/* - * We will implement inheritence that is based on what the parent's SEC_DESC - * says, but the Owner and Group SIDs can be overwridden from the command line - * and additional ACEs can be applied from the command line etc. - */ -static KEY_SEC_DESC *nt_inherit_security(struct registry_key *key) +static DATA_BLOB regf_get_data(const struct regf_data *data, uint32_t offset) { - - if (!key) return NULL; - return key->security; -} - -/* - * Create an initial security descriptor and init other structures, if needed - * We assume that the initial security stuff is empty ... - */ -static KEY_SEC_DESC *nt_create_init_sec(struct registry_hive *h) -{ - REGF *regf = h->backend_data; - KEY_SEC_DESC *tsec = NULL; - - tsec = malloc_p(KEY_SEC_DESC); - - tsec->ref_cnt = 1; - tsec->state = SEC_DESC_NBK; - tsec->offset = 0; - - tsec->sec_desc = regf->def_sec_desc; - - return tsec; + int i; + DATA_BLOB ret; + ret.data = NULL; + ret.length = 0; + + for (i = 0; data->hbins[i]; i++) { + if (offset >= data->hbins[i]->offset_from_first && + offset < data->hbins[i]->offset_from_first+ + data->hbins[i]->offset_to_next) + break; + } + + if (data->hbins[i] == NULL) { + DEBUG(1, ("Can't find HBIN containing 0x%4x\n", offset)); + return ret; + } + + ret.length = IVAL(data->hbins[i]->data, + offset - data->hbins[i]->offset_from_first - 0x20); + if (ret.length & 0x80000000) { + /* absolute value */ + ret.length = (ret.length ^ 0xffffffff) + 1; + } + ret.data = data->hbins[i]->data + + (offset - data->hbins[i]->offset_from_first - 0x20) + 4; + + return ret; } -#endif -/* - * Get the starting record for NT Registry file - */ -/* - * Where we keep all the regf stuff for one registry. - * This is the structure that we use to tie the in memory tree etc - * together. By keeping separate structs, we can operate on different - * registries at the same time. - * Currently, the SK_MAP is an array of mapping structure. - * Since we only need this on input and output, we fill in the structure - * as we go on input. On output, we know how many SK items we have, so - * we can allocate the structure as we need to. - * If you add stuff here that is dynamically allocated, add the - * appropriate free statements below. - */ - -#define REG_HANDLE_REGTYPE_NONE 0 -#define REG_HANDLE_REGTYPE_NT 1 -#define REG_HANDLE_REGTYPE_W9X 2 - -#define TTTONTTIME(r, t1, t2) (r)->last_mod_time = (t1) | (((uint64_t)(t2)) << 32) - -#define REGF_HDR_BLKSIZ 0x1000 - -#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) -#define LOCN(base, f) ((base) + OFF(f)) - -/* Get the header of the registry. Return a pointer to the structure - * If the mmap'd area has not been allocated, then mmap the input file - */ -static REGF_HDR *nt_get_regf_hdr(struct registry_hive *h) +static WERROR regf_num_subkeys (struct registry_key *key, uint32_t *count) { - REGF *regf = h->backend_data; - SMB_ASSERT(regf); - - if (!regf->base) { /* Try to mmap etc the file */ + struct nk_block *nk = key->backend_data; - if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) { - return NULL; /* What about errors? */ - } - - if (fstat(regf->fd, ®f->sbuf) < 0) { - return NULL; - } - - regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0); - - if ((int)regf->base == 1) { - DEBUG(0,("Could not mmap file: %s, %s\n", h->location, - strerror(errno))); - return NULL; - } - } - - /* - * At this point, regf->base != NULL, and we should be able to read the - * header - */ - - SMB_ASSERT(regf->base != NULL); - - return (REGF_HDR *)regf->base; -} - -/* - * Validate a regf header - * For now, do nothing, but we should check the checksum - */ -static int valid_regf_hdr(REGF_HDR *regf_hdr) -{ - if (!regf_hdr) return 0; - - return 1; -} - -#if 0 - -/* - * Process an SK header ... - * Every time we see a new one, add it to the map. Otherwise, just look it up. - * We will do a simple linear search for the moment, since many KEYs have the - * same security descriptor. - * We allocate the map in increments of 10 entries. - */ - -/* - * Create a new entry in the map, and increase the size of the map if needed - */ -static SK_MAP *alloc_sk_map_entry(struct registry_hive *h, KEY_SEC_DESC *tmp, int sk_off) -{ - REGF *regf = h->backend_data; - if (!regf->sk_map) { /* Allocate a block of 10 */ - regf->sk_map = malloc_array_p(SK_MAP, 10); - regf->sk_map_size = 10; - regf->sk_count = 1; - (regf->sk_map)[0].sk_off = sk_off; - (regf->sk_map)[0].key_sec_desc = tmp; - } - else { /* Simply allocate a new slot, unless we have to expand the list */ - int ndx = regf->sk_count; - if (regf->sk_count >= regf->sk_map_size) { - regf->sk_map = (SK_MAP *)realloc(regf->sk_map, - (regf->sk_map_size + 10)*sizeof(SK_MAP)); - if (!regf->sk_map) { - free(tmp); - return NULL; - } - /* - * ndx already points at the first entry of the new block - */ - regf->sk_map_size += 10; - } - (regf->sk_map)[ndx].sk_off = sk_off; - (regf->sk_map)[ndx].key_sec_desc = tmp; - regf->sk_count++; - } - return regf->sk_map; + *count = nk->num_subkeys; + + return WERR_OK; } -/* - * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not - * found - */ -KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off) +static WERROR regf_num_values (struct registry_key *key, uint32_t *count) { - int i; + struct nk_block *nk = key->backend_data; - if (!sk_map) return NULL; - - for (i = 0; i < count; i++) { - - if (sk_map[i].sk_off == sk_off) - return sk_map[i].key_sec_desc; - - } - - return NULL; + *count = nk->num_values; + return WERR_OK; } -/* - * Allocate a KEY_SEC_DESC if we can't find one in the map - */ -static KEY_SEC_DESC *lookup_create_sec_key(struct registry_hive *h, SK_MAP *sk_map, int sk_off) +static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset) { - REGF *regf = h->backend_data; - KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off); + DATA_BLOB data = regf_get_data(regf, offset); + struct tdr_pull *pull; + struct registry_key *ret; + struct nk_block *nk; - if (tmp) { - return tmp; - } - else { /* Allocate a new one */ - tmp = malloc_p(KEY_SEC_DESC); - memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */ - tmp->state = SEC_DESC_RES; - if (!alloc_sk_map_entry(h, tmp, sk_off)) { - return NULL; - } - return tmp; - } -} - -static SEC_DESC *process_sec_desc(struct registry_hive *regf, SEC_DESC *sec_desc) -{ - SEC_DESC *tmp = NULL; - - tmp = malloc_p(SEC_DESC); - - tmp->revision = SVAL(&sec_desc->revision,0); - tmp->type = SVAL(&sec_desc->type,0); - DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type)); - DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0))); - DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0))); - DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0))); - tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0))); - if (!tmp->owner_sid) { - free(tmp); + if (data.data == NULL) { + DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset)); return NULL; } - tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0))); - if (!tmp->grp_sid) { - free(tmp); - return NULL; - } - - /* Now pick up the SACL and DACL */ - - DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0))); - - if (sec_desc->off_sacl) - tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0))); - else - tmp->sacl = NULL; - - if (sec_desc->off_dacl) - tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0))); - else - tmp->dacl = NULL; - - return tmp; -} -static KEY_SEC_DESC *process_sk(struct registry_hive *regf, SK_HDR *sk_hdr, int sk_off, int size) -{ - KEY_SEC_DESC *tmp = NULL; - int sk_next_off, sk_prev_off, sk_size; - SEC_DESC *sec_desc; - - if (!sk_hdr) return NULL; + ret = talloc_zero(ctx, struct registry_key); + pull = talloc_zero(ret, struct tdr_pull); + pull->data = data; + nk = talloc(ret, struct nk_block); - if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) { - DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr, - regf->regfile_name)); + if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, nk))) { + DEBUG(1, ("Error parsing 'nk' record\n")); + talloc_free(ret); return NULL; } - if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) { - DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n", - -size, sk_size, regf->regfile_name)); + if (strcmp(nk->header, "nk") != 0) { + DEBUG(0, ("Expected nk record, got %s\n", nk->header)); + talloc_free(ret); return NULL; } - /* - * Now, we need to look up the SK Record in the map, and return it - * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can - * use that - */ - - if (regf->sk_map && - ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL) - && (tmp->state == SEC_DESC_OCU)) { - tmp->ref_cnt++; - return tmp; - } - - /* Here, we have an item in the map that has been reserved, or tmp==NULL. */ - - SMB_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON)); - - /* - * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the - * new KEY_SEC_DESC to the mapping structure, since the offset supplied is - * the actual offset of structure. The same offset will be used by - * all future references to this structure - * We could put all this unpleasantness in a function. - */ - - if (!tmp) { - tmp = malloc_p(KEY_SEC_DESC); - memset(tmp, 0, sizeof(KEY_SEC_DESC)); - - /* - * Allocate an entry in the SK_MAP ... - * We don't need to free tmp, because that is done for us if the - * sm_map entry can't be expanded when we need more space in the map. - */ - - if (!alloc_sk_map_entry(regf, tmp, sk_off)) { - return NULL; - } - } - - tmp->ref_cnt++; - tmp->state = SEC_DESC_OCU; - - /* - * Now, process the actual sec desc and plug the values in - */ + ret->name = talloc_steal(ret, nk->key_name); + ret->last_mod = nk->last_change; + ret->class_name = NULL; /* FIXME: get somehow using clsname_offset */ + ret->backend_data = nk; - sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0]; - tmp->sec_desc = process_sec_desc(regf, sec_desc); - - /* - * Now forward and back links. Here we allocate an entry in the sk_map - * if it does not exist, and mark it reserved - */ - - sk_prev_off = IVAL(&sk_hdr->prev_off,0); - tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off); - SMB_ASSERT(tmp->prev != NULL); - sk_next_off = IVAL(&sk_hdr->next_off,0); - tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off); - SMB_ASSERT(tmp->next != NULL); - - return tmp; + return ret; } -#endif -/* - * Process a VK header and return a value - */ -static WERROR vk_to_val(TALLOC_CTX *mem_ctx, struct registry_key *parent, VK_HDR *vk_hdr, int size, struct registry_value **value) +static WERROR regf_get_value (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_value **ret) { - REGF *regf = parent->hive->backend_data; - int nam_len, dat_len, flag, dat_type, dat_off, vk_id; - struct registry_value *tmp = NULL; - - if (!vk_hdr) return WERR_INVALID_PARAM; - - if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) { - DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n", - vk_id, (int)vk_hdr, parent->hive->location)); + struct nk_block *nk = key->backend_data; + struct vk_block *vk; + struct tdr_pull *pull; + uint32_t vk_offset; + DATA_BLOB data; + + if (idx >= nk->num_values) + return WERR_NO_MORE_ITEMS; + + data = regf_get_data(key->hive->backend_data, nk->values_offset); + if (!data.data) { + DEBUG(0, ("Unable to find value list\n")); return WERR_GENERAL_FAILURE; } - nam_len = SVAL(&vk_hdr->nam_len,0); - flag = SVAL(&vk_hdr->flag,0); - dat_type = IVAL(&vk_hdr->dat_type,0); - dat_len = IVAL(&vk_hdr->dat_len,0); /* If top bit, offset contains data */ - dat_off = IVAL(&vk_hdr->dat_off,0); - - tmp = talloc(mem_ctx, struct registry_value); - tmp->data_type = dat_type; - - if (flag & FLAG_HAS_NAME) { - tmp->name = talloc_strndup(mem_ctx, vk_hdr->dat_name, nam_len); - } else { - tmp->name = NULL; + if (data.length < nk->num_values * 4) { + DEBUG(1, ("Value counts mismatch\n")); } - /* - * Allocate space and copy the data as a BLOB - */ - - if (dat_len&0x7FFFFFFF) { - - char *dtmp = talloc_size(mem_ctx, dat_len&0x7FFFFFFF); + vk_offset = IVAL(data.data, idx * 4); - if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */ - char *dat_ptr = LOCN(regf->base, dat_off); - memcpy(dtmp, dat_ptr, dat_len); - } - else { /* The data is in the offset or type */ - /* - * FIXME. - * Some registry files seem to have weird fields. If top bit is set, - * but len is 0, the type seems to be the value ... - * Not sure how to handle this last type for the moment ... - */ - dat_len = dat_len & 0x7FFFFFFF; - memcpy(dtmp, &dat_off, dat_len); - } - - tmp->data = data_blob_talloc(mem_ctx, dtmp, dat_len); + data = regf_get_data(key->hive->backend_data, vk_offset); + if (!data.data) { + DEBUG(0, ("Unable to find value\n")); + return WERR_GENERAL_FAILURE; } - *value = tmp; - return WERR_OK; -} + *ret = talloc_zero(ctx, struct registry_value); + if (!(*ret)) + return WERR_NOMEM; -#if 0 /* unused */ + vk = talloc(*ret, struct vk_block); + if (!vk) + return WERR_NOMEM; + + pull = talloc_zero(*ret, struct tdr_pull); + pull->data = data; -static BOOL vl_verify(VL_TYPE vl, int count, int size) -{ - if(!vl) return False; - if (-size < (count+1)*sizeof(int)){ - DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size)); - return False; + if (NT_STATUS_IS_ERR(tdr_pull_vk_block(pull, vk))) { + DEBUG(0, ("Error parsing vk block\n")); + return WERR_GENERAL_FAILURE; } - return True; -} - -#endif -static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size) -{ - int lf_id; - if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) { - DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n", - lf_id, (int)lf_hdr, h->location)); - return WERR_INVALID_PARAM; + (*ret)->name = talloc_steal(*ret, vk->data_name); + (*ret)->data_type = vk->data_type; + if (vk->data_length & 0x80000000) { + vk->data_length &= ~0x80000000; + (*ret)->data.data = (uint8_t *)&vk->data_offset; + (*ret)->data.length = vk->data_length; + } else { + (*ret)->data = regf_get_data(key->hive->backend_data, vk->data_offset); } - return WERR_OK; -} - -static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, uint32_t *count) -{ - WERROR error; - - error = lf_verify(h, lf_hdr, size); - if(!W_ERROR_IS_OK(error)) return error; - - SMB_ASSERT(size < 0); - - *count = SVAL(&lf_hdr->key_count,0); - DEBUG(2, ("Key Count: %u\n", *count)); - if (*count <= 0) return WERR_INVALID_PARAM; + if ((*ret)->data.length < vk->data_length) { + DEBUG(1, ("Read data less then indicated data length!\n")); + } + return WERR_OK; } - -static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **); - - - -/* - * Process an LF Header and return a list of sub-keys - */ -static WERROR lf_get_entry(TALLOC_CTX *mem_ctx, struct registry_key *parent, LF_HDR *lf_hdr, int size, int n, struct registry_key **key) +static WERROR regf_get_subkey (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_key **ret) { - REGF *regf = parent->hive->backend_data; - int count, nk_off; - NK_HDR *nk_hdr; - WERROR error; - - if (!lf_hdr) return WERR_INVALID_PARAM; - - error = lf_verify(parent->hive, lf_hdr, size); - if(!W_ERROR_IS_OK(error)) return error; - - SMB_ASSERT(size < 0); + DATA_BLOB data; + struct nk_block *nk = key->backend_data; + uint32_t key_off; - count = SVAL(&lf_hdr->key_count,0); - DEBUG(2, ("Key Count: %u\n", count)); - if (count <= 0) return WERR_GENERAL_FAILURE; - if (n >= count) return WERR_NO_MORE_ITEMS; + if (idx >= nk->num_subkeys) + return WERR_NO_MORE_ITEMS; - nk_off = IVAL(&lf_hdr->hr[n].nk_off,0); - DEBUG(2, ("NK Offset: %0X\n", nk_off)); - nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off); - return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key); -} - -static WERROR nk_to_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **key) -{ - REGF *regf = h->backend_data; - struct registry_key *tmp = NULL, *own; - int namlen, clsname_len, sk_off, own_off; - uint_t nk_id; - SK_HDR *sk_hdr; - int type; - char key_name[1024]; - - if (!nk_hdr) return WERR_INVALID_PARAM; - - if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) { - DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", - nk_id, (int)nk_hdr, parent->hive->location)); - return WERR_INVALID_PARAM; - } - - SMB_ASSERT(size < 0); - - namlen = SVAL(&nk_hdr->nam_len,0); - clsname_len = SVAL(&nk_hdr->clsnam_len,0); - - /* - * The value of -size should be ge - * (sizeof(NK_HDR) - 1 + namlen) - * The -1 accounts for the fact that we included the first byte of - * the name in the structure. clsname_len is the length of the thing - * pointed to by clsnam_off - */ - - if (-size < (sizeof(NK_HDR) - 1 + namlen)) { - DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr)); - DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n", - (int)sizeof(NK_HDR), namlen, clsname_len)); + data = regf_get_data(key->hive->backend_data, nk->subkeys_offset); + if (!data.data) { + DEBUG(0, ("Unable to find subkey list\n")); return WERR_GENERAL_FAILURE; } - DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len)); + if (!strncmp((char *)data.data, "li", 2)) { + DEBUG(4, ("Subkeys in LI list\n")); + SMB_ASSERT(0); + } else if (!strncmp((char *)data.data, "lf", 2)) { + struct lf_block lf; + struct tdr_pull *pull = talloc_zero(ctx, struct tdr_pull); - /* Fish out the key name and process the LF list */ + DEBUG(10, ("Subkeys in LF list\n")); + pull->data = data; - SMB_ASSERT(namlen < sizeof(key_name)); + if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, &lf))) { + DEBUG(0, ("Error parsing LF list\n")); + return WERR_GENERAL_FAILURE; + } - strncpy(key_name, nk_hdr->key_nam, namlen); - key_name[namlen] = '\0'; + if (lf.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } - type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY); - if(type == REG_ROOT_KEY && parent) { - DEBUG(0,("Root key encountered below root level!\n")); + key_off = lf.hr[idx].nk_off; + + talloc_free(pull); + } else if (!strncmp((char *)data.data, "ri", 2)) { + DEBUG(4, ("Subkeys in RI list\n")); + SMB_ASSERT(0); + } else if (!strncmp((char *)data.data, "lh", 2)) { + DEBUG(4, ("Subkeys in LH list\n")); + SMB_ASSERT(0); + } else { + DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1])); return WERR_GENERAL_FAILURE; } - tmp = talloc(mem_ctx, struct registry_key); - tmp->name = talloc_strdup(mem_ctx, key_name); - tmp->backend_data = nk_hdr; - - DEBUG(2, ("Key name: %s\n", key_name)); - - /* - * Fish out the class name, it is in UNICODE, while the key name is - * ASCII :-) - */ - - if (clsname_len) { /* Just print in Ascii for now */ - void *clsnamep; - int clsnam_off; - - clsnam_off = IVAL(&nk_hdr->clsnam_off,0); - clsnamep = LOCN(regf->base, clsnam_off); - DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off)); - - pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep); - - DEBUGADD(2,(" Class Name: %s\n", tmp->class_name)); - - } - - /* - * Process the owner offset ... - */ - - own_off = IVAL(&nk_hdr->own_off,0); - own = (struct registry_key *)LOCN(regf->base, own_off); - DEBUG(2, ("Owner Offset: %0X\n", own_off)); - - DEBUGADD(2, (" Owner locn: %0X, Our locn: %0X\n", - (uint_t)own, (uint_t)nk_hdr)); + *ret = regf_get_key (ctx, key->hive->backend_data, key_off); - /* - * We should verify that the owner field is correct ... - * for now, we don't worry ... - */ - - /* - * Also handle the SK header ... - */ - - sk_off = IVAL(&nk_hdr->sk_off,0); - sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off); - DEBUG(2, ("SK Offset: %0X\n", sk_off)); - - if (sk_off != -1) { - -#if 0 - tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr)); -#endif - - } - - *key = tmp; return WERR_OK; } -#if 0 /* unused */ - -/* - * Allocate a new hbin block, set up the header for the block etc - */ -static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size) -{ - REGF *regf = h->backend_data; - HBIN_BLK *tmp; - HBIN_HDR *hdr; - - if (!regf || !size) return NULL; - - /* Round size up to multiple of REGF_HDR_BLKSIZ */ - - size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1); - - tmp = malloc_p(HBIN_BLK); - memset(tmp, 0, sizeof(HBIN_BLK)); - - tmp->data = malloc(size); - - memset(tmp->data, 0, size); /* Make it pristine */ - - tmp->size = size; - /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/ - - tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR)); - tmp->fsp_off = size - tmp->free_space; - - /* - * Now, build the header in the data block - */ - hdr = (HBIN_HDR *)tmp->data; - hdr->HBIN_ID = str_to_dword("hbin"); - hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ; - hdr->off_to_next = tmp->size; - hdr->blk_size = tmp->size; - - /* - * Now link it in - */ - - regf->blk_tail->next = tmp; - regf->blk_tail = tmp; - if (!regf->free_space) regf->free_space = tmp; - - return tmp; -} - -/* - * Allocate a unit of space ... and return a pointer as function param - * and the block's offset as a side effect - */ -static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off) -{ - REGF *regf = h->backend_data; - int tmp = 0; - void *ret = NULL; - HBIN_BLK *blk; - - if (!regf || !size || !off) return NULL; - - SMB_ASSERT(regf->blk_head != NULL); - - /* - * round up size to include header and then to 8-byte boundary - */ - size = (size + 4 + 7) & ~7; - - /* - * Check if there is space, if none, grab a block - */ - if (!regf->free_space) { - if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) - return NULL; - } - - /* - * Now, chain down the list of blocks looking for free space - */ - - for (blk = regf->free_space; blk != NULL; blk = blk->next) { - if (blk->free_space <= size) { - tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; - ret = blk->data + blk->fsp_off; - blk->free_space -= size; - blk->fsp_off += size; - - /* Insert the header */ - ((HBIN_SUB_HDR *)ret)->dblocksize = -size; - - /* - * Fix up the free space ptr - * If it is NULL, we fix it up next time - */ - - if (!blk->free_space) - regf->free_space = blk->next; - - *off = tmp; - return (((char *)ret)+4);/* The pointer needs to be to the data struct */ - } - } - - /* - * If we got here, we need to add another block, which might be - * larger than one block -- deal with that later - */ - if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) { - blk = regf->free_space; - tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; - ret = blk->data + blk->fsp_off; - blk->free_space -= size; - blk->fsp_off += size; - - /* Insert the header */ - ((HBIN_SUB_HDR *)ret)->dblocksize = -size; - - /* - * Fix up the free space ptr - * If it is NULL, we fix it up next time - */ - - if (!blk->free_space) - regf->free_space = blk->next; - - *off = tmp; - return (((char *)ret) + 4);/* The pointer needs to be to the data struct */ - } - - return NULL; -} - -/* - * Store a SID at the location provided - */ -static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn) +static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key) { + struct regf_data *regf; + struct regf_hdr *regf_hdr; + struct tdr_pull *pull; int i; - uint8_t *p = locn; - - if (!regf || !sid || !locn) return 0; - - *p = sid->sid_rev_num; p++; - *p = sid->num_auths; p++; - - for (i=0; i < 6; i++) { - *p = sid->id_auth[i]; p++; - } - - for (i=0; i < sid->num_auths; i++) { - SIVAL(p, 0, sid->sub_auths[i]); p+=4; - } - - return p - locn; - -} - -static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn) -{ - int size = 0; - SEC_ACE *reg_ace = (SEC_ACE *)locn; - uint8_t *p; - - if (!regf || !ace || !locn) return 0; - - reg_ace->type = ace->type; - reg_ace->flags = ace->flags; - - /* Deal with the length when we have stored the SID */ - - p = (uint8_t *)®_ace->info.mask; - - SIVAL(p, 0, ace->info.mask); p += 4; - - size = nt_store_SID(regf, &ace->trustee, p); - - size += 8; /* Size of the fixed header */ - - p = (uint8_t *)®_ace->size; - - SSVAL(p, 0, size); - - return size; -} - -/* - * Store an ACL at the location provided - */ -static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) { - int size = 0, i; - uint8_t *p = locn, *s; - - if (!regf || !acl || !locn) return 0; - - /* - * Now store the header and then the ACEs ... - */ - - SSVAL(p, 0, acl->revision); - - p += 2; s = p; /* Save this for the size field */ - - p += 2; - - SIVAL(p, 0, acl->num_aces); - - p += 4; - - for (i = 0; i < acl->num_aces; i++) { - size = nt_store_ace(regf, &acl->ace[i], p); - p += size; - } - - size = s - locn; - SSVAL(s, 0, size); - return size; -} - -/* - * Flatten and store the Sec Desc - * Windows lays out the DACL first, but since there is no SACL, it might be - * that first, then the owner, then the group SID. So, we do it that way - * too. - */ -static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn) -{ - SEC_DESC *rsd = (SEC_DESC *)locn; - uint_t size = 0, off = 0; - - if (!regf || !sd || !locn) return 0; - - /* - * Now, fill in the first two fields, then lay out the various fields - * as needed - */ - - rsd->revision = SEC_DESC_REVISION; - rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE; - - off = 4 * sizeof(uint32_t) + 4; - - if (sd->sacl){ - size = nt_store_acl(regf, sd->sacl, (char *)(locn + off)); - rsd->off_sacl = off; - } - else - rsd->off_sacl = 0; - - off += size; - - if (sd->dacl) { - rsd->off_dacl = off; - size = nt_store_acl(regf, sd->dacl, (char *)(locn + off)); - } - else { - rsd->off_dacl = 0; - } - off += size; - - /* Now the owner and group SIDs */ - - if (sd->owner_sid) { - rsd->off_owner_sid = off; - size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off)); - } - else { - rsd->off_owner_sid = 0; - } - - off += size; - - if (sd->grp_sid) { - rsd->off_grp_sid = off; - size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off)); - } - else { - rsd->off_grp_sid = 0; - } - - off += size; - - return size; -} - -/* - * Store the security information - * - * If it has already been stored, just get its offset from record - * otherwise, store it and record its offset - */ -static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec) -{ - int size = 0; - uint_t sk_off; - SK_HDR *sk_hdr; - - if (sec->offset) return sec->offset; - - /* - * OK, we don't have this one in the file yet. We must compute the - * size taken by the security descriptor as a self-relative SD, which - * means making one pass over each structure and figuring it out - */ - -/* FIXME size = sec_desc_size(sec->sec_desc); */ - - /* Allocate that much space */ - - sk_hdr = nt_alloc_regf_space(regf, size, &sk_off); - sec->sk_hdr = sk_hdr; - - if (!sk_hdr) return 0; - - /* Now, lay out the sec_desc in the space provided */ - - sk_hdr->SK_ID = str_to_dword("sk"); - - /* - * We can't deal with the next and prev offset in the SK_HDRs until the - * whole tree has been stored, then we can go and deal with them - */ - - sk_hdr->ref_cnt = sec->ref_cnt; - sk_hdr->rec_size = size; /* Is this correct */ - - /* Now, lay out the sec_desc */ - - if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc)) - return 0; - - return sk_off; - -} - -/* - * Store a KEY in the file ... - * - * We store this depth first, and defer storing the lf struct until - * all the sub-keys have been stored. - * - * We store the NK hdr, any SK header, class name, and VK structure, then - * recurse down the LF structures ... - * - * We return the offset of the NK struct - * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ... - */ -static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key) -{ - NK_HDR *nk_hdr; - uint_t nk_off, sk_off, size; - - if (!regf || !key) return 0; - - size = sizeof(NK_HDR) + strlen(key->name) - 1; - nk_hdr = nt_alloc_regf_space(regf, size, &nk_off); - if (!nk_hdr) goto error; - - key->offset = nk_off; /* We will need this later */ - - /* - * Now fill in each field etc ... - */ - - nk_hdr->NK_ID = str_to_dword("nk"); - if (key->type == REG_ROOT_KEY) - nk_hdr->type = 0x2C; - else - nk_hdr->type = 0x20; - - /* FIXME: Fill in the time of last update */ - - if (key->type != REG_ROOT_KEY) - nk_hdr->own_off = key->owner->offset; - - if (key->sub_keys) - nk_hdr->subk_num = key->sub_keys->key_count; - - /* - * Now, process the Sec Desc and then store its offset - */ - - sk_off = nt_store_security(regf, key->security); - nk_hdr->sk_off = sk_off; - - /* - * Then, store the val list and store its offset - */ - if (key->values) { - nk_hdr->val_cnt = key->values->val_count; - nk_hdr->val_off = nt_store_val_list(regf, key->values); - } - else { - nk_hdr->val_off = -1; - nk_hdr->val_cnt = 0; - } - - /* - * Finally, store the subkeys, and their offsets - */ - -error: - return 0; -} - -/* - * Store the registry header ... - * We actually create the registry header block and link it to the chain - * of output blocks. - */ -static REGF_HDR *nt_get_reg_header(struct registry_hive *h) { - REGF *regf = h->backend_data; - HBIN_BLK *tmp = NULL; - - tmp = malloc_p(HBIN_BLK); - - memset(tmp, 0, sizeof(HBIN_BLK)); - tmp->type = REG_OUTBLK_HDR; - tmp->size = REGF_HDR_BLKSIZ; - tmp->data = malloc(REGF_HDR_BLKSIZ); - if (!tmp->data) goto error; - - memset(tmp->data, 0, REGF_HDR_BLKSIZ); /* Make it pristine, unlike Windows */ - regf->blk_head = regf->blk_tail = tmp; - - return (REGF_HDR *)tmp->data; - -error: - if (tmp) free(tmp); - return NULL; -} - -#endif - -static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key) -{ - REGF *regf; - REGF_HDR *regf_hdr; - uint_t regf_id, hbin_id; - HBIN_HDR *hbin_hdr; - - regf = (REGF *)talloc(h, REGF); - memset(regf, 0, sizeof(REGF)); - regf->owner_sid_str = NULL; /* FIXME: Fill in */ + regf = (struct regf_data *)talloc_zero(h, struct regf_data); h->backend_data = regf; DEBUG(5, ("Attempting to load registry file\n")); /* Get the header */ - if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) { - DEBUG(0, ("Unable to get header\n")); + regf->data.data = (uint8_t *)file_load(h->location, ®f->data.length, regf); + if (regf->data.data == NULL) { + DEBUG(0,("Could not load file: %s, %s\n", h->location, + strerror(errno))); return WERR_GENERAL_FAILURE; } - /* Now process that header and start to read the rest in */ + pull = talloc_zero(regf, struct tdr_pull); + if (!pull) + return WERR_NOMEM; - if ((regf_id = IVAL(®f_hdr->REGF_ID,0)) != str_to_dword("regf")) { - DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n", - regf_id, h->location)); - return WERR_GENERAL_FAILURE; - } + pull->data = regf->data; - /* - * Validate the header ... - */ - if (!valid_regf_hdr(regf_hdr)) { - DEBUG(0, ("Registry file header does not validate: %s\n", - h->location)); + regf_hdr = talloc(regf, struct regf_hdr); + if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr))) { return WERR_GENERAL_FAILURE; } - /* Update the last mod date, and then go get the first NK record and on */ - - TTTONTTIME(regf, IVAL(®f_hdr->tim1,0), IVAL(®f_hdr->tim2,0)); - - /* - * The hbin hdr seems to be just uninteresting garbage. Check that - * it is there, but that is all. - */ + if (strcmp(regf_hdr->REGF_ID, "regf") != 0) { + DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n", + regf_hdr->REGF_ID, h->location)); + } - hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ); - - if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) { - DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", - hbin_id, h->location)); - return WERR_GENERAL_FAILURE; - } + DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n", + regf_hdr->description, regf_hdr->version.major, + regf_hdr->version.minor, regf_hdr->version.release, + regf_hdr->version.build)); /* - * Get a pointer to the first key from the hreg_hdr + * Validate the header ... */ + if (regf_hdr_checksum(regf->data.data) != regf_hdr->chksum) { + DEBUG(0, ("Registry file checksum error: %s: %d,%d\n", + h->location, regf_hdr->chksum, regf_hdr_checksum(regf->data.data))); + return WERR_GENERAL_FAILURE; + } - DEBUG(2, ("First Key: %0X\n", - IVAL(®f_hdr->first_key, 0))); - - regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(®f_hdr->first_key,0)); - DEBUGADD(2, ("First Key Offset: %0X\n", - IVAL(®f_hdr->first_key, 0))); - - DEBUGADD(2, ("Data Block Size: %d\n", - IVAL(®f_hdr->dblk_size, 0))); - - DEBUGADD(2, ("Offset to next hbin block: %0X\n", - IVAL(&hbin_hdr->off_to_next, 0))); + pull->offset = 0x1000; - DEBUGADD(2, ("HBIN block size: %0X\n", - IVAL(&hbin_hdr->blk_size, 0))); + i = 0; + /* Read in all hbin blocks */ + regf->hbins = talloc_array(regf, struct hbin_block *, 1); + regf->hbins[0] = NULL; - /* - * Unmap the registry file, as we might want to read in another - * tree etc. - */ + while (pull->offset < pull->data.length) { + struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block); - h->backend_data = regf; + if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin))) { + DEBUG(0, ("[%d] Error parsing HBIN block\n", i)); + return WERR_FOOBAR; + } - return nk_to_key(h, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key); -} + if (strcmp(hbin->HBIN_ID, "hbin") != 0) { + DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID)); + return WERR_FOOBAR; + } + regf->hbins[i] = hbin; + i++; + regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2); + regf->hbins[i] = NULL; + } -static WERROR nt_num_subkeys(struct registry_key *k, uint32_t *num) -{ - REGF *regf = k->hive->backend_data; - LF_HDR *lf_hdr; - int lf_off; - NK_HDR *nk_hdr = k->backend_data; - lf_off = IVAL(&nk_hdr->lf_off,0); - DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); - if(lf_off == -1) { - *num = 0; - return WERR_OK; - } - lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); + DEBUG(1, ("%d HBIN blocks read\n", i)); - return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num); -} + *key = regf_get_key(h, regf, 0x20); -static WERROR nt_num_values(struct registry_key *k, uint32_t *count) -{ - NK_HDR *nk_hdr = k->backend_data; - *count = IVAL(&nk_hdr->val_cnt,0); return WERR_OK; } -static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value) -{ - VL_TYPE *vl; - int val_off, vk_off; - int val_count; - VK_HDR *vk_hdr; - REGF *regf = k->hive->backend_data; - NK_HDR *nk_hdr = k->backend_data; - val_count = IVAL(&nk_hdr->val_cnt,0); - val_off = IVAL(&nk_hdr->val_off,0); - vl = (VL_TYPE *)LOCN(regf->base, val_off); - DEBUG(2, ("Val List Offset: %0X\n", val_off)); - if(n < 0) return WERR_INVALID_PARAM; - if(n >= val_count) return WERR_NO_MORE_ITEMS; - - vk_off = IVAL(&vl[n],0); - vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off); - return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value); -} - -static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey) -{ - REGF *regf = k->hive->backend_data; - int lf_off; - NK_HDR *nk_hdr = k->backend_data; - LF_HDR *lf_hdr; - lf_off = IVAL(&nk_hdr->lf_off,0); - DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); - - /* - * No more subkeys if lf_off == -1 - */ - - if (lf_off != -1) { - lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey); - } - - return WERR_NO_MORE_ITEMS; -} - static struct hive_operations reg_backend_nt4 = { .name = "nt4", .open_hive = nt_open_hive, - .num_subkeys = nt_num_subkeys, - .num_values = nt_num_values, - .get_subkey_by_index = nt_key_by_index, - .get_value_by_index = nt_value_by_index, - - /* TODO: - .add_key - .add_value - .del_key - .del_value - .update_value - */ + .num_subkeys = regf_num_subkeys, + .num_values = regf_num_values, + .get_subkey_by_index = regf_get_subkey, + .get_value_by_index = regf_get_value, }; NTSTATUS registry_nt4_init(void) diff --git a/source4/lib/registry/regf.idl b/source4/lib/registry/regf.idl index 03f63debc8..760183c01d 100644 --- a/source4/lib/registry/regf.idl +++ b/source4/lib/registry/regf.idl @@ -13,13 +13,15 @@ interface regf { + const int REGF_OFFSET_NONE = 0xffffffff; + /* * Registry version number * 1.3.0.1 for WinNT 4 * 1.5.0.1 for WinXP */ - typedef struct { + typedef [noprint] struct { [value(1)] uint32 major; [value(3)] uint32 minor; [value(0)] uint32 release; @@ -33,7 +35,7 @@ interface regf the first 0x200 bytes only! */ - typedef [public] struct { + typedef [public,noprint] struct { [charset(DOS)] uint8 REGF_ID[4]; /* 'regf' */ uint32 update_counter1; uint32 update_counter2; @@ -53,23 +55,21 @@ interface regf This block is always a multiple of 4kb in size. */ - typedef [public] struct { + typedef [public,noprint] struct { [charset(DOS)] uint8 HBIN_ID[4]; /* hbin */ - uint32 off_from_first; /* Offset from 1st hbin-Block */ - uint32 off_to_next; /* Offset to the next hbin-Block */ + uint32 offset_from_first; /* Offset from 1st hbin-Block */ + uint32 offset_to_next; /* Offset to the next hbin-Block */ uint32 unknown[2]; NTTIME last_change; - uint32 block_size; /* Block size */ - uint8 data[block_size]; /* Filled with hbin_data blocks */ + uint32 block_size; /* Block size (including the header!) */ + uint8 data[offset_to_next-0x20]; + /* data is filled with: + uint32 length + uint8_t data[length] + */ } hbin_block; - typedef struct { - uint32 length; - [charset(DOS)] uint8 header[2]; /* li, lh, ri, nk, vk, sk, lf or \0\0 */ - uint8 data[length-2]; - } hbin_data; - - typedef enum { + typedef [base_type(uint16),noprint] enum { REG_ROOT_KEY = 0x20, REG_SUB_KEY = 0x2C, REG_SYM_LINK = 0x10 @@ -79,7 +79,8 @@ interface regf The nk-record can be treated as a combination of tree-record and key-record of the win 95 registry. */ - typedef struct { + typedef [public,noprint] struct { + [charset(DOS)] uint8 header[2]; reg_key_type type; NTTIME last_change; uint32 uk1; @@ -87,19 +88,20 @@ interface regf uint32 num_subkeys; uint32 uk2; uint32 subkeys_offset; - uint32 uk3; + uint32 unknown_offset; uint32 num_values; - uint32 values_offset; + uint32 values_offset; /* Points to a list of offsets of vk-records */ uint32 sk_offset; uint32 clsname_offset; - uint32 unk4[5]; + uint32 unk3[5]; uint16 name_length; uint16 clsname_length; [charset(DOS)] uint8 key_name[name_length]; } nk_block; /* sk (? Security Key ?) is the ACL of the registry. */ - typedef struct { + typedef [noprint,nopush,nopull] struct { + [charset(DOS)] uint8 header[2]; uint16 uk1; uint32 prev_offset; uint32 next_offset; @@ -108,39 +110,43 @@ interface regf uint8 sec_desc[rec_size]; } sk_block; - typedef struct { + typedef [noprint,nopush,nopull] struct { uint32 offset_nk; uint32 base37; /* base37 of key name */ } lh_hash; /* Subkey listing with hash of first 4 characters */ - typedef struct { + typedef [noprint,nopush,nopull] struct { + [charset(DOS)] uint8 header[2]; uint16 key_count; lh_hash hashes[key_count]; } lh_block; - typedef struct { + typedef [noprint,nopush,nopull] struct { + [charset(DOS)] uint8 header[2]; uint16 key_count; uint32 offset_nk[key_count]; } li_block; - typedef struct { + typedef [noprint,nopush,nopull] struct { + [charset(DOS)] uint8 header[2]; uint16 key_count; uint32 offset[key_count]; /* li/lh offset */ } ri_block; /* The vk-record consists information to a single value (value key). */ - typedef struct { + typedef [public,noprint] struct { + [charset(DOS)] uint8 header[2]; uint16 name_length; uint32 data_length; /* If top-bit set, offset contains the data */ uint32 data_offset; uint32 data_type; uint16 flag; /* =1, has name, else no name (=Default). */ uint16 unk1; - [charset(DOS)] uint8 data_name[name_length]; + [charset(DOS)] uint8 data_name[name_length]; } vk_block; - typedef struct { + typedef [noprint] struct { uint32 nk_off; uint8 hash[4]; } hash_record; @@ -149,7 +155,8 @@ interface regf The lf-record is the counterpart to the RGKN-record (the hash-function) */ - typedef struct { + typedef [public,noprint] struct { + [charset(DOS)] uint8 header[2]; uint16 key_count; hash_record hr[key_count]; /* Array of hash records, depending on key_count */ } lf_block; diff --git a/source4/pidl/lib/Parse/Pidl/IDL.pm b/source4/pidl/lib/Parse/Pidl/IDL.pm index a73451d142..203e052022 100644 --- a/source4/pidl/lib/Parse/Pidl/IDL.pm +++ b/source4/pidl/lib/Parse/Pidl/IDL.pm @@ -559,7 +559,7 @@ sub new { } }, {#State 9 - DEFAULT => -89 + DEFAULT => -92 }, {#State 10 ACTIONS => { @@ -643,7 +643,7 @@ sub new { } }, {#State 22 - DEFAULT => -93 + DEFAULT => -96 }, {#State 23 DEFAULT => -74 @@ -653,32 +653,35 @@ sub new { }, {#State 25 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "(" => 41, - "|" => 42, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -69 }, {#State 26 ACTIONS => { - "," => 46, - ")" => 47 + "," => 49, + ")" => 50 } }, {#State 27 DEFAULT => -75 }, {#State 28 - DEFAULT => -92 + DEFAULT => -95 }, {#State 29 DEFAULT => -66 @@ -688,38 +691,38 @@ sub new { }, {#State 31 ACTIONS => { - "typedef" => 48, - "union" => 49, - "enum" => 62, - "bitmap" => 63, - "declare" => 55, - "const" => 57, - "struct" => 60 + "typedef" => 51, + "union" => 52, + "enum" => 65, + "bitmap" => 66, + "declare" => 58, + "const" => 60, + "struct" => 63 }, DEFAULT => -63, GOTOS => { - 'typedecl' => 61, - 'function' => 50, - 'bitmap' => 64, - 'definitions' => 51, - 'definition' => 54, - 'property_list' => 53, - 'usertype' => 52, - 'declare' => 66, - 'const' => 65, - 'struct' => 56, - 'enum' => 58, - 'typedef' => 59, - 'union' => 67 + 'typedecl' => 64, + 'function' => 53, + 'bitmap' => 67, + 'definitions' => 54, + 'definition' => 57, + 'property_list' => 56, + 'usertype' => 55, + 'declare' => 69, + 'const' => 68, + 'struct' => 59, + 'enum' => 61, + 'typedef' => 62, + 'union' => 70 } }, {#State 32 ACTIONS => { - ";" => 68 + ";" => 71 }, - DEFAULT => -94, + DEFAULT => -97, GOTOS => { - 'optional_semicolon' => 69 + 'optional_semicolon' => 72 } }, {#State 33 @@ -727,7 +730,7 @@ sub new { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 70 + 'identifier' => 73 } }, {#State 34 @@ -739,7 +742,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 71, + 'anytext' => 74, 'text' => 24, 'constant' => 27 } @@ -753,7 +756,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 72, + 'anytext' => 75, 'text' => 24, 'constant' => 27 } @@ -767,7 +770,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 73, + 'anytext' => 76, 'text' => 24, 'constant' => 27 } @@ -781,7 +784,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 74, + 'anytext' => 77, 'text' => 24, 'constant' => 27 } @@ -795,10 +798,9 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 75, + 'anytext' => 78, 'text' => 24, - 'constant' => 27, - 'commalisttext' => 76 + 'constant' => 27 } }, {#State 39 @@ -810,7 +812,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 77, + 'anytext' => 79, 'text' => 24, 'constant' => 27 } @@ -824,9 +826,10 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 78, + 'anytext' => 80, 'text' => 24, - 'constant' => 27 + 'constant' => 27, + 'commalisttext' => 81 } }, {#State 41 @@ -838,10 +841,9 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 75, + 'anytext' => 82, 'text' => 24, - 'constant' => 27, - 'commalisttext' => 79 + 'constant' => 27 } }, {#State 42 @@ -853,7 +855,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 80, + 'anytext' => 83, 'text' => 24, 'constant' => 27 } @@ -867,7 +869,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 81, + 'anytext' => 84, 'text' => 24, 'constant' => 27 } @@ -881,9 +883,10 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 82, + 'anytext' => 80, 'text' => 24, - 'constant' => 27 + 'constant' => 27, + 'commalisttext' => 85 } }, {#State 45 @@ -895,7 +898,7 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 83, + 'anytext' => 86, 'text' => 24, 'constant' => 27 } @@ -909,406 +912,544 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 84, + 'anytext' => 87, 'text' => 24, 'constant' => 27 } }, {#State 47 - DEFAULT => -68 + ACTIONS => { + 'CONSTANT' => 28, + 'TEXT' => 22, + 'IDENTIFIER' => 9 + }, + DEFAULT => -73, + GOTOS => { + 'identifier' => 23, + 'anytext' => 88, + 'text' => 24, + 'constant' => 27 + } }, {#State 48 - DEFAULT => -63, + ACTIONS => { + 'CONSTANT' => 28, + 'TEXT' => 22, + 'IDENTIFIER' => 9 + }, + DEFAULT => -73, GOTOS => { - 'property_list' => 85 + 'identifier' => 23, + 'anytext' => 89, + 'text' => 24, + 'constant' => 27 } }, {#State 49 ACTIONS => { - 'IDENTIFIER' => 86 + 'CONSTANT' => 28, + 'TEXT' => 22, + 'IDENTIFIER' => 9 }, - DEFAULT => -91, + DEFAULT => -73, GOTOS => { - 'optional_identifier' => 87 + 'identifier' => 23, + 'anytext' => 90, + 'text' => 24, + 'constant' => 27 } }, {#State 50 - DEFAULT => -12 + DEFAULT => -68 }, {#State 51 - ACTIONS => { - "}" => 88, - "typedef" => 48, - "union" => 49, - "enum" => 62, - "bitmap" => 63, - "declare" => 55, - "const" => 57, - "struct" => 60 - }, DEFAULT => -63, GOTOS => { - 'typedecl' => 61, - 'function' => 50, - 'bitmap' => 64, - 'definition' => 89, - 'property_list' => 53, - 'usertype' => 52, - 'const' => 65, - 'struct' => 56, - 'declare' => 66, - 'enum' => 58, - 'typedef' => 59, - 'union' => 67 + 'property_list' => 91 } }, {#State 52 ACTIONS => { - ";" => 90 + 'IDENTIFIER' => 92 + }, + DEFAULT => -94, + GOTOS => { + 'optional_identifier' => 93 } }, {#State 53 + DEFAULT => -12 + }, + {#State 54 + ACTIONS => { + "}" => 94, + "typedef" => 51, + "union" => 52, + "enum" => 65, + "bitmap" => 66, + "declare" => 58, + "const" => 60, + "struct" => 63 + }, + DEFAULT => -63, + GOTOS => { + 'typedecl' => 64, + 'function' => 53, + 'bitmap' => 67, + 'definition' => 95, + 'property_list' => 56, + 'usertype' => 55, + 'const' => 68, + 'struct' => 59, + 'declare' => 69, + 'enum' => 61, + 'typedef' => 62, + 'union' => 70 + } + }, + {#State 55 + ACTIONS => { + ";" => 96 + } + }, + {#State 56 ACTIONS => { 'IDENTIFIER' => 9, - "union" => 49, - "enum" => 62, - "bitmap" => 63, + "union" => 52, + "enum" => 65, + "bitmap" => 66, "[" => 7, - 'void' => 91, - "struct" => 60 + 'void' => 97, + "struct" => 63 }, GOTOS => { - 'identifier' => 93, - 'struct' => 56, - 'enum' => 58, - 'type' => 94, - 'union' => 67, - 'bitmap' => 64, - 'usertype' => 92 + 'identifier' => 99, + 'struct' => 59, + 'enum' => 61, + 'type' => 100, + 'union' => 70, + 'bitmap' => 67, + 'usertype' => 98 } }, - {#State 54 + {#State 57 DEFAULT => -10 }, - {#State 55 + {#State 58 DEFAULT => -63, GOTOS => { - 'property_list' => 95 + 'property_list' => 101 } }, - {#State 56 + {#State 59 DEFAULT => -26 }, - {#State 57 + {#State 60 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 96 + 'identifier' => 102 } }, - {#State 58 + {#State 61 DEFAULT => -28 }, - {#State 59 + {#State 62 DEFAULT => -14 }, - {#State 60 + {#State 63 ACTIONS => { - 'IDENTIFIER' => 86 + 'IDENTIFIER' => 92 }, - DEFAULT => -91, + DEFAULT => -94, GOTOS => { - 'optional_identifier' => 97 + 'optional_identifier' => 103 } }, - {#State 61 + {#State 64 DEFAULT => -16 }, - {#State 62 + {#State 65 ACTIONS => { - 'IDENTIFIER' => 86 + 'IDENTIFIER' => 92 }, - DEFAULT => -91, + DEFAULT => -94, GOTOS => { - 'optional_identifier' => 98 + 'optional_identifier' => 104 } }, - {#State 63 + {#State 66 ACTIONS => { - 'IDENTIFIER' => 86 + 'IDENTIFIER' => 92 }, - DEFAULT => -91, + DEFAULT => -94, GOTOS => { - 'optional_identifier' => 99 + 'optional_identifier' => 105 } }, - {#State 64 + {#State 67 DEFAULT => -29 }, - {#State 65 + {#State 68 DEFAULT => -13 }, - {#State 66 + {#State 69 DEFAULT => -15 }, - {#State 67 + {#State 70 DEFAULT => -27 }, - {#State 68 - DEFAULT => -95 + {#State 71 + DEFAULT => -98 }, - {#State 69 + {#State 72 DEFAULT => -4 }, - {#State 70 + {#State 73 ACTIONS => { - ";" => 100 + ";" => 106 } }, - {#State 71 + {#State 74 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 + }, + DEFAULT => -86 + }, + {#State 75 + ACTIONS => { + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -77 }, - {#State 72 + {#State 76 + ACTIONS => { + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 + }, + DEFAULT => -85 + }, + {#State 77 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "*" => 43, - "{" => 38, - "&" => 39, - "/" => 40, - "(" => 41, - "|" => 42, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -81 }, - {#State 73 + {#State 78 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "*" => 43, - "{" => 38, - "&" => 39, - "/" => 40, - "(" => 41, - "|" => 42, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, - DEFAULT => -86 + DEFAULT => -89 }, - {#State 74 + {#State 79 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, - DEFAULT => -85 + DEFAULT => -88 }, - {#State 75 + {#State 80 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "*" => 43, - "{" => 38, - "&" => 39, - "/" => 40, - "(" => 41, - "|" => 42, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -71 }, - {#State 76 + {#State 81 ACTIONS => { - "}" => 101, - "," => 102 + "}" => 107, + "," => 108 } }, - {#State 77 + {#State 82 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -83 }, - {#State 78 + {#State 83 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -84 }, - {#State 79 + {#State 84 ACTIONS => { - "," => 102, - ")" => 103 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 + }, + DEFAULT => -87 + }, + {#State 85 + ACTIONS => { + "," => 108, + ")" => 109 } }, - {#State 80 + {#State 86 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -82 }, - {#State 81 + {#State 87 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -79 }, - {#State 82 + {#State 88 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -78 }, - {#State 83 + {#State 89 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, DEFAULT => -80 }, - {#State 84 + {#State 90 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -70 }, - {#State 85 + {#State 91 ACTIONS => { 'IDENTIFIER' => 9, - "union" => 49, - "enum" => 62, - "bitmap" => 63, + "union" => 52, + "enum" => 65, + "bitmap" => 66, "[" => 7, - 'void' => 91, - "struct" => 60 + 'void' => 97, + "struct" => 63 }, GOTOS => { - 'identifier' => 93, - 'struct' => 56, - 'enum' => 58, - 'type' => 104, - 'union' => 67, - 'bitmap' => 64, - 'usertype' => 92 + 'identifier' => 99, + 'struct' => 59, + 'enum' => 61, + 'type' => 110, + 'union' => 70, + 'bitmap' => 67, + 'usertype' => 98 } }, - {#State 86 - DEFAULT => -90 + {#State 92 + DEFAULT => -93 }, - {#State 87 + {#State 93 ACTIONS => { - "{" => 105 + "{" => 111 } }, - {#State 88 + {#State 94 ACTIONS => { - ";" => 68 + ";" => 71 }, - DEFAULT => -94, + DEFAULT => -97, GOTOS => { - 'optional_semicolon' => 106 + 'optional_semicolon' => 112 } }, - {#State 89 + {#State 95 DEFAULT => -11 }, - {#State 90 + {#State 96 DEFAULT => -30 }, - {#State 91 + {#State 97 DEFAULT => -33 }, - {#State 92 + {#State 98 DEFAULT => -31 }, - {#State 93 + {#State 99 DEFAULT => -32 }, - {#State 94 + {#State 100 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 107 + 'identifier' => 113 } }, - {#State 95 + {#State 101 ACTIONS => { - "enum" => 111, - "bitmap" => 112, + "enum" => 117, + "bitmap" => 118, "[" => 7 }, GOTOS => { - 'decl_enum' => 108, - 'decl_bitmap' => 109, - 'decl_type' => 110 + 'decl_enum' => 114, + 'decl_bitmap' => 115, + 'decl_type' => 116 } }, - {#State 96 + {#State 102 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 113 + 'identifier' => 119 } }, - {#State 97 + {#State 103 ACTIONS => { - "{" => 114 + "{" => 120 } }, - {#State 98 + {#State 104 ACTIONS => { - "{" => 115 + "{" => 121 } }, - {#State 99 + {#State 105 ACTIONS => { - "{" => 116 + "{" => 122 } }, - {#State 100 + {#State 106 DEFAULT => -6 }, - {#State 101 + {#State 107 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1317,12 +1458,12 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 117, + 'anytext' => 123, 'text' => 24, 'constant' => 27 } }, - {#State 102 + {#State 108 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1331,12 +1472,12 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 118, + 'anytext' => 124, 'text' => 24, 'constant' => 27 } }, - {#State 103 + {#State 109 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1345,188 +1486,197 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 119, + 'anytext' => 125, 'text' => 24, 'constant' => 27 } }, - {#State 104 + {#State 110 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 120 + 'identifier' => 126 } }, - {#State 105 + {#State 111 DEFAULT => -48, GOTOS => { - 'union_elements' => 121 + 'union_elements' => 127 } }, - {#State 106 + {#State 112 DEFAULT => -7 }, - {#State 107 + {#State 113 ACTIONS => { - "(" => 122 + "(" => 128 } }, - {#State 108 + {#State 114 DEFAULT => -21 }, - {#State 109 + {#State 115 DEFAULT => -22 }, - {#State 110 + {#State 116 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 123 + 'identifier' => 129 } }, - {#State 111 + {#State 117 DEFAULT => -23 }, - {#State 112 + {#State 118 DEFAULT => -24 }, - {#State 113 + {#State 119 ACTIONS => { - "[" => 124, - "=" => 126 + "[" => 130, + "=" => 132 }, GOTOS => { - 'array_len' => 125 + 'array_len' => 131 } }, - {#State 114 + {#State 120 DEFAULT => -54, GOTOS => { - 'element_list1' => 127 + 'element_list1' => 133 } }, - {#State 115 + {#State 121 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 128, - 'enum_element' => 129, - 'enum_elements' => 130 + 'identifier' => 134, + 'enum_element' => 135, + 'enum_elements' => 136 } }, - {#State 116 + {#State 122 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 133, - 'bitmap_elements' => 132, - 'bitmap_element' => 131 + 'identifier' => 139, + 'bitmap_elements' => 138, + 'bitmap_element' => 137 } }, - {#State 117 + {#State 123 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "*" => 43, - "{" => 38, - "&" => 39, - "/" => 40, - "(" => 41, - "|" => 42, - "." => 44, - ">" => 45 - }, - DEFAULT => -88 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 + }, + DEFAULT => -91 }, - {#State 118 + {#State 124 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "*" => 43, - "{" => 38, - "&" => 39, - "/" => 40, - "(" => 41, - "|" => 42, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -72 }, - {#State 119 + {#State 125 ACTIONS => { - "<" => 35, - "~" => 36, - "{" => 38 + ":" => 34, + "<" => 37, + "~" => 38, + "?" => 36, + "{" => 40, + "=" => 43 }, - DEFAULT => -87 + DEFAULT => -90 }, - {#State 120 + {#State 126 ACTIONS => { - "[" => 124 + "[" => 130 }, DEFAULT => -60, GOTOS => { - 'array_len' => 134 + 'array_len' => 140 } }, - {#State 121 + {#State 127 ACTIONS => { - "}" => 135 + "}" => 141 }, DEFAULT => -63, GOTOS => { - 'optional_base_element' => 137, - 'property_list' => 136 + 'optional_base_element' => 143, + 'property_list' => 142 } }, - {#State 122 + {#State 128 ACTIONS => { "," => -56, - "void" => 141, + "void" => 147, ")" => -56 }, DEFAULT => -63, GOTOS => { - 'base_element' => 138, - 'element_list2' => 140, - 'property_list' => 139 + 'base_element' => 144, + 'element_list2' => 146, + 'property_list' => 145 } }, - {#State 123 + {#State 129 ACTIONS => { - ";" => 142 + ";" => 148 } }, - {#State 124 + {#State 130 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, - "]" => 143, + "]" => 149, 'IDENTIFIER' => 9 }, DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 144, + 'anytext' => 150, 'text' => 24, 'constant' => 27 } }, - {#State 125 + {#State 131 ACTIONS => { - "=" => 145 + "=" => 151 } }, - {#State 126 + {#State 132 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1535,135 +1685,138 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 146, + 'anytext' => 152, 'text' => 24, 'constant' => 27 } }, - {#State 127 + {#State 133 ACTIONS => { - "}" => 147 + "}" => 153 }, DEFAULT => -63, GOTOS => { - 'base_element' => 148, - 'property_list' => 139 + 'base_element' => 154, + 'property_list' => 145 } }, - {#State 128 + {#State 134 ACTIONS => { - "=" => 149 + "=" => 155 }, DEFAULT => -37 }, - {#State 129 + {#State 135 DEFAULT => -35 }, - {#State 130 + {#State 136 ACTIONS => { - "}" => 150, - "," => 151 + "}" => 156, + "," => 157 } }, - {#State 131 + {#State 137 DEFAULT => -40 }, - {#State 132 + {#State 138 ACTIONS => { - "}" => 152, - "," => 153 + "}" => 158, + "," => 159 } }, - {#State 133 + {#State 139 ACTIONS => { - "=" => 154 + "=" => 160 } }, - {#State 134 + {#State 140 ACTIONS => { - ";" => 155 + ";" => 161 } }, - {#State 135 + {#State 141 DEFAULT => -50 }, - {#State 136 + {#State 142 ACTIONS => { "[" => 7 }, DEFAULT => -63, GOTOS => { - 'base_or_empty' => 156, - 'base_element' => 157, - 'empty_element' => 158, - 'property_list' => 159 + 'base_or_empty' => 162, + 'base_element' => 163, + 'empty_element' => 164, + 'property_list' => 165 } }, - {#State 137 + {#State 143 DEFAULT => -49 }, - {#State 138 + {#State 144 DEFAULT => -58 }, - {#State 139 + {#State 145 ACTIONS => { 'IDENTIFIER' => 9, - "union" => 49, - "enum" => 62, - "bitmap" => 63, + "union" => 52, + "enum" => 65, + "bitmap" => 66, "[" => 7, - 'void' => 91, - "struct" => 60 + 'void' => 97, + "struct" => 63 }, GOTOS => { - 'identifier' => 93, - 'struct' => 56, - 'enum' => 58, - 'type' => 160, - 'union' => 67, - 'bitmap' => 64, - 'usertype' => 92 + 'identifier' => 99, + 'struct' => 59, + 'enum' => 61, + 'type' => 166, + 'union' => 70, + 'bitmap' => 67, + 'usertype' => 98 } }, - {#State 140 + {#State 146 ACTIONS => { - "," => 161, - ")" => 162 + "," => 167, + ")" => 168 } }, - {#State 141 + {#State 147 DEFAULT => -57 }, - {#State 142 + {#State 148 DEFAULT => -20 }, - {#State 143 + {#State 149 ACTIONS => { - "[" => 124 + "[" => 130 }, DEFAULT => -60, GOTOS => { - 'array_len' => 163 + 'array_len' => 169 } }, - {#State 144 + {#State 150 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - "]" => 164, - ">" => 45 + "-" => 35, + ":" => 34, + "?" => 36, + "<" => 37, + "+" => 39, + "~" => 38, + "&" => 41, + "{" => 40, + "/" => 42, + "=" => 43, + "|" => 45, + "(" => 44, + "*" => 46, + "." => 47, + "]" => 170, + ">" => 48 } }, - {#State 145 + {#State 151 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1672,37 +1825,40 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 165, + 'anytext' => 171, 'text' => 24, 'constant' => 27 } }, - {#State 146 + {#State 152 ACTIONS => { - "-" => 34, - "<" => 35, - ";" => 166, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "?" => 36, + "<" => 37, + ";" => 172, + "+" => 39, + "~" => 38, + "&" => 41, + "{" => 40, + "/" => 42, + "=" => 43, + "|" => 45, + "(" => 44, + "*" => 46, + "." => 47, + ">" => 48 } }, - {#State 147 + {#State 153 DEFAULT => -43 }, - {#State 148 + {#State 154 ACTIONS => { - ";" => 167 + ";" => 173 } }, - {#State 149 + {#State 155 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1711,36 +1867,36 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 168, + 'anytext' => 174, 'text' => 24, 'constant' => 27 } }, - {#State 150 + {#State 156 DEFAULT => -34 }, - {#State 151 + {#State 157 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 128, - 'enum_element' => 169 + 'identifier' => 134, + 'enum_element' => 175 } }, - {#State 152 + {#State 158 DEFAULT => -39 }, - {#State 153 + {#State 159 ACTIONS => { 'IDENTIFIER' => 9 }, GOTOS => { - 'identifier' => 133, - 'bitmap_element' => 170 + 'identifier' => 139, + 'bitmap_element' => 176 } }, - {#State 154 + {#State 160 ACTIONS => { 'CONSTANT' => 28, 'TEXT' => 22, @@ -1749,179 +1905,188 @@ sub new { DEFAULT => -73, GOTOS => { 'identifier' => 23, - 'anytext' => 171, + 'anytext' => 177, 'text' => 24, 'constant' => 27 } }, - {#State 155 + {#State 161 DEFAULT => -25 }, - {#State 156 + {#State 162 DEFAULT => -47 }, - {#State 157 + {#State 163 ACTIONS => { - ";" => 172 + ";" => 178 } }, - {#State 158 + {#State 164 DEFAULT => -46 }, - {#State 159 + {#State 165 ACTIONS => { 'IDENTIFIER' => 9, - "union" => 49, - ";" => 173, - "enum" => 62, - "bitmap" => 63, - 'void' => 91, + "union" => 52, + ";" => 179, + "enum" => 65, + "bitmap" => 66, + 'void' => 97, "[" => 7, - "struct" => 60 + "struct" => 63 }, GOTOS => { - 'identifier' => 93, - 'struct' => 56, - 'enum' => 58, - 'type' => 160, - 'union' => 67, - 'bitmap' => 64, - 'usertype' => 92 + 'identifier' => 99, + 'struct' => 59, + 'enum' => 61, + 'type' => 166, + 'union' => 70, + 'bitmap' => 67, + 'usertype' => 98 } }, - {#State 160 + {#State 166 DEFAULT => -52, GOTOS => { - 'pointers' => 174 + 'pointers' => 180 } }, - {#State 161 + {#State 167 DEFAULT => -63, GOTOS => { - 'base_element' => 175, - 'property_list' => 139 + 'base_element' => 181, + 'property_list' => 145 } }, - {#State 162 + {#State 168 ACTIONS => { - ";" => 176 + ";" => 182 } }, - {#State 163 + {#State 169 DEFAULT => -61 }, - {#State 164 + {#State 170 ACTIONS => { - "[" => 124 + "[" => 130 }, DEFAULT => -60, GOTOS => { - 'array_len' => 177 + 'array_len' => 183 } }, - {#State 165 + {#State 171 ACTIONS => { - "-" => 34, - "<" => 35, - ";" => 178, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "?" => 36, + "<" => 37, + ";" => 184, + "+" => 39, + "~" => 38, + "&" => 41, + "{" => 40, + "/" => 42, + "=" => 43, + "|" => 45, + "(" => 44, + "*" => 46, + "." => 47, + ">" => 48 } }, - {#State 166 + {#State 172 DEFAULT => -17 }, - {#State 167 + {#State 173 DEFAULT => -55 }, - {#State 168 + {#State 174 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -38 }, - {#State 169 + {#State 175 DEFAULT => -36 }, - {#State 170 + {#State 176 DEFAULT => -41 }, - {#State 171 + {#State 177 ACTIONS => { - "-" => 34, - "<" => 35, - "+" => 37, - "~" => 36, - "&" => 39, - "{" => 38, - "/" => 40, - "|" => 42, - "(" => 41, - "*" => 43, - "." => 44, - ">" => 45 + "-" => 35, + ":" => 34, + "<" => 37, + "+" => 39, + "~" => 38, + "*" => 46, + "?" => 36, + "{" => 40, + "&" => 41, + "/" => 42, + "=" => 43, + "(" => 44, + "|" => 45, + "." => 47, + ">" => 48 }, DEFAULT => -42 }, - {#State 172 + {#State 178 DEFAULT => -45 }, - {#State 173 + {#State 179 DEFAULT => -44 }, - {#State 174 + {#State 180 ACTIONS => { 'IDENTIFIER' => 9, - "*" => 180 + "*" => 186 }, GOTOS => { - 'identifier' => 179 + 'identifier' => 185 } }, - {#State 175 + {#State 181 DEFAULT => -59 }, - {#State 176 + {#State 182 DEFAULT => -19 }, - {#State 177 + {#State 183 DEFAULT => -62 }, - {#State 178 + {#State 184 DEFAULT => -18 }, - {#State 179 + {#State 185 ACTIONS => { - "[" => 124 + "[" => 130 }, DEFAULT => -60, GOTOS => { - 'array_len' => 181 + 'array_len' => 187 } }, - {#State 180 + {#State 186 DEFAULT => -53 }, - {#State 181 + {#State 187 DEFAULT => -51 } ], @@ -1936,19 +2101,19 @@ sub new { [#Rule 2 'idl', 2, sub -#line 19 "idl.yp" +#line 19 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 3 'idl', 2, sub -#line 20 "idl.yp" +#line 20 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 4 'coclass', 7, sub -#line 24 "idl.yp" +#line 24 "pidl/idl.yp" {$_[3] => { "TYPE" => "COCLASS", "PROPERTIES" => $_[1], @@ -1964,13 +2129,13 @@ sub [#Rule 6 'interface_names', 4, sub -#line 36 "idl.yp" +#line 36 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 7 'interface', 8, sub -#line 40 "idl.yp" +#line 40 "pidl/idl.yp" {$_[3] => { "TYPE" => "INTERFACE", "PROPERTIES" => $_[1], @@ -1987,19 +2152,19 @@ sub [#Rule 9 'base_interface', 2, sub -#line 53 "idl.yp" +#line 53 "pidl/idl.yp" { $_[2] } ], [#Rule 10 'definitions', 1, sub -#line 57 "idl.yp" +#line 57 "pidl/idl.yp" { [ $_[1] ] } ], [#Rule 11 'definitions', 2, sub -#line 58 "idl.yp" +#line 58 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 12 @@ -2020,7 +2185,7 @@ sub [#Rule 17 'const', 6, sub -#line 66 "idl.yp" +#line 66 "pidl/idl.yp" {{ "TYPE" => "CONST", "DTYPE" => $_[2], @@ -2033,7 +2198,7 @@ sub [#Rule 18 'const', 7, sub -#line 75 "idl.yp" +#line 75 "pidl/idl.yp" {{ "TYPE" => "CONST", "DTYPE" => $_[2], @@ -2047,7 +2212,7 @@ sub [#Rule 19 'function', 7, sub -#line 88 "idl.yp" +#line 88 "pidl/idl.yp" {{ "TYPE" => "FUNCTION", "NAME" => $_[3], @@ -2061,7 +2226,7 @@ sub [#Rule 20 'declare', 5, sub -#line 100 "idl.yp" +#line 100 "pidl/idl.yp" {{ "TYPE" => "DECLARE", "PROPERTIES" => $_[2], @@ -2080,7 +2245,7 @@ sub [#Rule 23 'decl_enum', 1, sub -#line 114 "idl.yp" +#line 114 "pidl/idl.yp" {{ "TYPE" => "ENUM" }} @@ -2088,7 +2253,7 @@ sub [#Rule 24 'decl_bitmap', 1, sub -#line 120 "idl.yp" +#line 120 "pidl/idl.yp" {{ "TYPE" => "BITMAP" }} @@ -2096,7 +2261,7 @@ sub [#Rule 25 'typedef', 6, sub -#line 126 "idl.yp" +#line 126 "pidl/idl.yp" {{ "TYPE" => "TYPEDEF", "PROPERTIES" => $_[2], @@ -2122,7 +2287,7 @@ sub [#Rule 30 'typedecl', 2, sub -#line 139 "idl.yp" +#line 139 "pidl/idl.yp" { $_[1] } ], [#Rule 31 @@ -2134,13 +2299,13 @@ sub [#Rule 33 'type', 1, sub -#line 142 "idl.yp" +#line 142 "pidl/idl.yp" { "void" } ], [#Rule 34 'enum', 5, sub -#line 146 "idl.yp" +#line 146 "pidl/idl.yp" {{ "TYPE" => "ENUM", "NAME" => $_[2], @@ -2150,13 +2315,13 @@ sub [#Rule 35 'enum_elements', 1, sub -#line 154 "idl.yp" +#line 154 "pidl/idl.yp" { [ $_[1] ] } ], [#Rule 36 'enum_elements', 3, sub -#line 155 "idl.yp" +#line 155 "pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 37 @@ -2165,13 +2330,13 @@ sub [#Rule 38 'enum_element', 3, sub -#line 159 "idl.yp" +#line 159 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 39 'bitmap', 5, sub -#line 163 "idl.yp" +#line 163 "pidl/idl.yp" {{ "TYPE" => "BITMAP", "NAME" => $_[2], @@ -2181,25 +2346,25 @@ sub [#Rule 40 'bitmap_elements', 1, sub -#line 171 "idl.yp" +#line 171 "pidl/idl.yp" { [ $_[1] ] } ], [#Rule 41 'bitmap_elements', 3, sub -#line 172 "idl.yp" +#line 172 "pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 42 'bitmap_element', 3, sub -#line 175 "idl.yp" +#line 175 "pidl/idl.yp" { "$_[1] ( $_[3] )" } ], [#Rule 43 'struct', 5, sub -#line 179 "idl.yp" +#line 179 "pidl/idl.yp" {{ "TYPE" => "STRUCT", "NAME" => $_[2], @@ -2209,7 +2374,7 @@ sub [#Rule 44 'empty_element', 2, sub -#line 187 "idl.yp" +#line 187 "pidl/idl.yp" {{ "NAME" => "", "TYPE" => "EMPTY", @@ -2229,7 +2394,7 @@ sub [#Rule 47 'optional_base_element', 2, sub -#line 201 "idl.yp" +#line 201 "pidl/idl.yp" { $_[2]->{PROPERTIES} = Parse::Pidl::Util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] } ], [#Rule 48 @@ -2238,13 +2403,13 @@ sub [#Rule 49 'union_elements', 2, sub -#line 206 "idl.yp" +#line 206 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 50 'union', 5, sub -#line 210 "idl.yp" +#line 210 "pidl/idl.yp" {{ "TYPE" => "UNION", "NAME" => $_[2], @@ -2254,7 +2419,7 @@ sub [#Rule 51 'base_element', 5, sub -#line 218 "idl.yp" +#line 218 "pidl/idl.yp" {{ "NAME" => $_[4], "TYPE" => $_[2], @@ -2268,13 +2433,13 @@ sub [#Rule 52 'pointers', 0, sub -#line 232 "idl.yp" +#line 232 "pidl/idl.yp" { 0 } ], [#Rule 53 'pointers', 2, sub -#line 233 "idl.yp" +#line 233 "pidl/idl.yp" { $_[1]+1 } ], [#Rule 54 @@ -2283,7 +2448,7 @@ sub [#Rule 55 'element_list1', 3, sub -#line 238 "idl.yp" +#line 238 "pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 56 @@ -2295,13 +2460,13 @@ sub [#Rule 58 'element_list2', 1, sub -#line 244 "idl.yp" +#line 244 "pidl/idl.yp" { [ $_[1] ] } ], [#Rule 59 'element_list2', 3, sub -#line 245 "idl.yp" +#line 245 "pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 60 @@ -2310,13 +2475,13 @@ sub [#Rule 61 'array_len', 3, sub -#line 250 "idl.yp" +#line 250 "pidl/idl.yp" { push(@{$_[3]}, "*"); $_[3] } ], [#Rule 62 'array_len', 4, sub -#line 251 "idl.yp" +#line 251 "pidl/idl.yp" { push(@{$_[4]}, "$_[2]"); $_[4] } ], [#Rule 63 @@ -2325,31 +2490,31 @@ sub [#Rule 64 'property_list', 4, sub -#line 257 "idl.yp" +#line 257 "pidl/idl.yp" { Parse::Pidl::Util::FlattenHash([$_[1],$_[3]]); } ], [#Rule 65 'properties', 1, sub -#line 260 "idl.yp" +#line 260 "pidl/idl.yp" { $_[1] } ], [#Rule 66 'properties', 3, sub -#line 261 "idl.yp" +#line 261 "pidl/idl.yp" { Parse::Pidl::Util::FlattenHash([$_[1], $_[3]]); } ], [#Rule 67 'property', 1, sub -#line 264 "idl.yp" +#line 264 "pidl/idl.yp" {{ "$_[1]" => "1" }} ], [#Rule 68 'property', 4, sub -#line 265 "idl.yp" +#line 265 "pidl/idl.yp" {{ "$_[1]" => "$_[3]" }} ], [#Rule 69 @@ -2358,7 +2523,7 @@ sub [#Rule 70 'listtext', 3, sub -#line 270 "idl.yp" +#line 270 "pidl/idl.yp" { "$_[1] $_[3]" } ], [#Rule 71 @@ -2367,13 +2532,13 @@ sub [#Rule 72 'commalisttext', 3, sub -#line 275 "idl.yp" +#line 275 "pidl/idl.yp" { "$_[1],$_[3]" } ], [#Rule 73 'anytext', 0, sub -#line 279 "idl.yp" +#line 279 "pidl/idl.yp" { "" } ], [#Rule 74 @@ -2388,97 +2553,115 @@ sub [#Rule 77 'anytext', 3, sub -#line 281 "idl.yp" +#line 281 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 78 'anytext', 3, sub -#line 282 "idl.yp" +#line 282 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 79 'anytext', 3, sub -#line 283 "idl.yp" +#line 283 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 80 'anytext', 3, sub -#line 284 "idl.yp" +#line 284 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 81 'anytext', 3, sub -#line 285 "idl.yp" +#line 285 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 82 'anytext', 3, sub -#line 286 "idl.yp" +#line 286 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 83 'anytext', 3, sub -#line 287 "idl.yp" +#line 287 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 84 'anytext', 3, sub -#line 288 "idl.yp" +#line 288 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 85 'anytext', 3, sub -#line 289 "idl.yp" +#line 289 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 86 'anytext', 3, sub -#line 290 "idl.yp" +#line 290 "pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 87 + 'anytext', 3, +sub +#line 291 "pidl/idl.yp" +{ "$_[1]$_[2]$_[3]" } + ], + [#Rule 88 + 'anytext', 3, +sub +#line 292 "pidl/idl.yp" +{ "$_[1]$_[2]$_[3]" } + ], + [#Rule 89 + 'anytext', 3, +sub +#line 293 "pidl/idl.yp" +{ "$_[1]$_[2]$_[3]" } + ], + [#Rule 90 'anytext', 5, sub -#line 291 "idl.yp" +#line 294 "pidl/idl.yp" { "$_[1]$_[2]$_[3]$_[4]$_[5]" } ], - [#Rule 88 + [#Rule 91 'anytext', 5, sub -#line 292 "idl.yp" +#line 295 "pidl/idl.yp" { "$_[1]$_[2]$_[3]$_[4]$_[5]" } ], - [#Rule 89 + [#Rule 92 'identifier', 1, undef ], - [#Rule 90 + [#Rule 93 'optional_identifier', 1, undef ], - [#Rule 91 + [#Rule 94 'optional_identifier', 0, undef ], - [#Rule 92 + [#Rule 95 'constant', 1, undef ], - [#Rule 93 + [#Rule 96 'text', 1, sub -#line 306 "idl.yp" +#line 309 "pidl/idl.yp" { "\"$_[1]\"" } ], - [#Rule 94 + [#Rule 97 'optional_semicolon', 0, undef ], - [#Rule 95 + [#Rule 98 'optional_semicolon', 1, undef ] ], @@ -2486,7 +2669,7 @@ sub bless($self,$class); } -#line 317 "idl.yp" +#line 320 "pidl/idl.yp" use Parse::Pidl::Util; -- cgit