Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / reactos / sdk / tools / hhpcomp / chmc / chmc.c
diff --git a/reactos/sdk/tools/hhpcomp/chmc/chmc.c b/reactos/sdk/tools/hhpcomp/chmc/chmc.c
deleted file mode 100644 (file)
index 50c4b46..0000000
+++ /dev/null
@@ -1,1692 +0,0 @@
-/*
-
-  Copyright(C) 2010 Alex Andreotti <alex.andreotti@gmail.com>
-
-  This file is part of chmc.
-
-  chmc is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  chmc is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with chmc.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-#include "chmc.h"
-
-#include <fcntl.h>
-
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-
-#if defined(_WIN32) || defined(__APPLE__)
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#else
-#ifdef __REACTOS__
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif /* __REACTOS__ */
-#include <unistd.h>
-#endif
-
-#include "err.h"
-
-
-#include "encint.h"
-
-#include <stdint.h>
-#include "../lzx_compress/lzx_config.h"
-#include "../lzx_compress/lzx_compress.h"
-
-#define PACKAGE_STRING "hhpcomp development version"
-
-/* if O_BINARY is not defined, the system is probably not expecting any such flag */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-int chmc_section_add(struct chmcFile *chm, const char *name);
-struct chmcSection * chmc_section_create(struct chmcFile *chm,
-                                         const char *name);
-void chmc_reset_table_init(struct chmcLzxcResetTable *reset_table);
-void chmc_control_data_init(struct chmcLzxcControlData *control_data);
-int chmc_namelist_create(struct chmcFile *chm, int len);
-struct chmcTreeNode * chmc_add_meta(struct chmcFile *chm,
-                                    const char *metaname, int sect_id,
-                                    UChar *buf, UInt64 len);
-struct chmcTreeNode *chmc_add_entry(struct chmcFile *chm, const char *name,
-                                    UInt16 prefixlen, int sect_id,
-                                    UChar *buf, UInt64 offset, UInt64 len);
-void chmc_sections_free(struct chmcFile *chm);
-void chmc_section_destroy(struct chmcSection *section);
-void chmc_pmgi_free(struct chmcFile *chm);
-void chmc_pmgl_free(struct chmcFile *chm);
-void chmc_pmgl_destroy(struct chmcPmglChunkNode *node);
-void chmc_pmgi_destroy(struct chmcPmgiChunkNode *node);
-void chmc_entries_free(struct chmcFile *chm);
-void chmc_entry_destroy(struct chmcTreeNode *node);
-int chmc_add_tree(struct chmcFile *chm, const char *dir);
-struct chmcTreeNode *chmc_add_file(struct chmcFile *chm, const char *filename,
-                                   UInt16 prefixlen, int sect_id, UChar *buf,
-                                   UInt64 len);
-struct chmcTreeNode *chmc_add_dir(struct chmcFile *chm, const char *dir);
-struct chmcTreeNode *chmc_add_empty(struct chmcFile *chm, const char *file);
-
-int chmc_crunch_lzx(struct chmcFile *chm, int sect_id);
-static int _lzx_at_eof(void *arg);
-static int _lzx_put_bytes(void *arg, int n, void *buf);
-static void _lzx_mark_frame(void *arg, uint32_t uncomp, uint32_t comp);
-static int _lzx_get_bytes(void *arg, int n, void *buf);
-
-int chmc_compressed_add_mark(struct chmcFile *chm, UInt64 at);
-int chmc_control_data_done(struct chmcFile *chm);
-int chmc_reset_table_done(struct chmcFile *chm);
-void chmc_pmgl_done(struct chmcFile *chm);
-
-void chmc_entries_qsort(struct chmcFile *chm);
-static int _entry_cmp(const void *pva, const void *pvb);
-
-struct chmcSection *chmc_section_lookup(struct chmcFile *chm, int id);
-
-struct chmcPmglChunkNode *chmc_pmgl_create(void);
-void chmc_pmgl_add(struct chmcFile *chm, struct chmcPmglChunkNode *pmgl);
-void chmc_pmgl_init(struct chmcPmglChunkNode *node);
-int chmc_pmgi_add_entry(struct chmcFile *chm, const char *name, int pmgl_id);
-void chmc_pmgi_add(struct chmcFile *chm, struct chmcPmgiChunkNode *pmgi);
-void chmc_string_init(struct chmcStringChunk *node);
-
-#ifdef __REACTOS__
-int chmc_uncompressed_done(struct chmcFile *chm);
-int chmc_pmgi_done(struct chmcFile *chm);
-int chmc_write(struct chmcFile *chm);
-int chmc_appendfile(struct chmcFile *chm, const char *filename, void *buf,
-                size_t size );
-int chmc_pmgl_add_entry(struct chmcFile *chm, struct chmcTreeNode *entry);
-#endif /* __REACTOS__ */
-
-struct chmcLzxInfo
-{
-       struct chmcFile *chm;
-       struct chmcSection *section;
-       int fd;
-       UInt32 fd_offset;
-       UInt32 done;
-       UInt32 todo;
-       struct list_head *pos;
-       int error;
-       int eof;
-};
-
-static const short chmc_transform_list[] = {
-       0x7b, 0x37, 0x46, 0x43, 0x32, 0x38, 0x39,
-       0x34, 0x30, 0x2d, 0x39, 0x44, 0x33, 0x31,
-       0x2d, 0x31, 0x31, 0x44, 0x30 };
-
-int chmc_init(struct chmcFile *chm, const char *filename,
-              struct chmcConfig *config)
-{
-       struct chmcItsfHeader *itsf = &chm->itsf;
-       struct chmcSect0 *sect0 = &chm->sect0;
-       struct chmcItspHeader *itsp = &chm->itsp;
-       struct chmcSystem *system = &chm->system;
-       struct chmcSystemInfo *sysinfo = &chm->system.info;
-       struct chmcIndexHeader *idxhdr = &chm->idxhdr;
-
-       assert(chm);
-       assert(filename);
-
-       chmcerr_clean();
-
-       memset(chm, 0, sizeof(struct chmcFile));
-
-       chm->config = config;
-
-       if (strcmp(filename, "-") != 0) {
-               chm->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
-               if (chm->fd < 0) {
-                       chmcerr_set(errno, strerror(errno));
-                       chmcerr_return_msg("creat file '%s'", filename);
-               }
-       } else {
-               chm->fd = fileno(stdout);
-       }
-
-       memcpy(itsf->signature, "ITSF", 4);
-       itsf->version = 3;
-       itsf->header_len = _CHMC_ITSF_V3_LEN;
-       itsf->unknown_000c = 1;
-
-       itsf->lang_id = chm->config->language;
-       memcpy(itsf->dir_uuid, CHMC_DIR_UUID, 16);
-       memcpy(itsf->stream_uuid, CHMC_STREAM_UUID, 16);
-       itsf->dir_offset = _CHMC_ITSF_V3_LEN + _CHMC_SECT0_LEN;
-
-       itsf->sect0_offset = _CHMC_ITSF_V3_LEN;
-       itsf->sect0_len = _CHMC_SECT0_LEN;
-
-       sect0->file_len = _CHMC_ITSF_V3_LEN
-               + _CHMC_SECT0_LEN
-               + _CHMC_ITSP_V1_LEN;
-
-       sect0->unknown_0000 = 510;
-
-       memcpy(itsp->signature, "ITSP", 4);
-       itsp->version = 1;
-       itsp->header_len = _CHMC_ITSP_V1_LEN;
-       itsp->unknown_000c = 10;
-       itsp->block_len = _CHMC_CHUNK_LEN;
-       itsp->blockidx_intvl = CHM_IDX_INTVL;
-       itsp->index_depth = 2;
-
-       itsp->unknown_0028 = -1;
-       itsp->lang_id = CHMC_MS_LCID_EN_US;
-       memcpy(itsp->system_uuid, CHMC_SYSTEM_UUID, 16);
-       itsp->header_len2 = _CHMC_ITSP_V1_LEN;
-       memset(itsp->unknown_0048, -1, 12);
-
-       system->version = 3;
-       system->_size = _CHMC_SYSTEM_HDR_LEN + sizeof(struct chmcIndexHeader);
-
-       sysinfo->lcid = CHMC_MS_LCID_EN_US;
-
-       memcpy(idxhdr->signature, "T#SM", 4);
-       idxhdr->unknown_4 = 28582569; // FIXME got from some chm
-       idxhdr->unknown_8 = 1;
-       //   idxhdr->full_search = 1;
-       //   idxhdr->klinks = 1;
-       //   idxhdr->alinks = 0;
-       //   idxhdr->timestamp = ???;
-
-       //   idxhdr->num_of_topic = 2; // sorry??
-       idxhdr->off_img_list = -1;
-       //   idxhdr->img_type_folder;
-       idxhdr->background = -1;
-       idxhdr->foreground = -1;
-       idxhdr->off_font = -1;
-       idxhdr->win_style = -1;
-       idxhdr->ex_win_style = -1;
-       idxhdr->unknown_34 = -1;
-       idxhdr->off_frame_name = -1;
-       idxhdr->off_win_name = -1;
-       //   idxhdr->num_of_info;
-       idxhdr->unknown_44 = 1;
-       //   idxhdr->num_of_merge_files;
-       //   idxhdr->unknown_4c;
-
-       INIT_LIST_HEAD(&chm->sections_list);
-       INIT_LIST_HEAD(&chm->pmgl_list);
-       INIT_LIST_HEAD(&chm->entries_list);
-       INIT_LIST_HEAD(&chm->pmgi_list);
-
-       chm->strings = malloc(4096);
-       memset(chm->strings, 0, 4096);
-       chm->strings_len = 4096;
-       chm->strings_offset = 1;
-
-       if (chmc_section_add(chm, "Uncompressed") != CHMC_NOERR)
-               chmcerr_return_msg("adding section: Uncompressed");
-
-       if (chmc_section_add(chm, "MSCompressed") != CHMC_NOERR)
-               chmcerr_return_msg("adding section: MSCompressed");
-
-       chmc_sections_done(chm);
-
-       return CHMC_NOERR;
-}
-
-int chmc_section_add(struct chmcFile *chm, const char *name)
-{
-       struct chmcSection *section;
-
-       assert(chm);
-       assert(name);
-
-       section = chmc_section_create(chm, name);
-       if (!section)
-               return chmcerr_code();
-
-       list_add_tail(&section->list, &chm->sections_list);
-       chm->sections_num++;
-
-       return CHMC_NOERR;
-}
-
-struct chmcSection *chmc_section_create(struct chmcFile *chm,
-                                        const char *name)
-{
-       struct chmcSection *section;
-
-       assert(name);
-
-       section = calloc(1, sizeof(struct chmcSection));
-       if (section) {
-               const char *tmpdir;
-               int len;
-
-               len = strlen(name);
-               memcpy(section->name, name, len + 1);
-               section->offset = 0;
-               section->len = 0;
-
-               tmpdir = NULL;
-               if (chm->config != NULL)
-                       tmpdir = chm->config->tmpdir;
-               if (tmpdir == NULL)
-                       tmpdir = "/tmp/";
-
-               len = strlen(tmpdir);
-               if (len >= PATH_MAX - 12) {
-                       chmcerr_set(errno, strerror(errno));
-                       chmcerr_msg("tmpdir too long: '%s'", tmpdir);
-                       goto fail;
-               }
-
-               strcat(section->filename, tmpdir);
-               if (section->filename[len - 1] != '/')
-                       strcat(section->filename, "/");
-
-               if (strcmp("MSCompressed", name) == 0)
-                       strcat(section->filename, "chmcCXXXXXX");
-               else
-                       strcat(section->filename, "chmcUXXXXXX");
-
-               section->fd = mkstemps(section->filename, 0);
-               fprintf(stderr, "temp file: %s\n", section->filename);
-               if (section->fd < 0) {
-                       chmcerr_set(errno, strerror(errno));
-                       chmcerr_msg("creat() file '%s'", section->filename);
-                       goto fail;
-               }
-               else if (strcmp(section->name, "MSCompressed") == 0) {
-                       chmc_reset_table_init(&section->reset_table_header);
-                       chmc_control_data_init(&section->control_data);
-                       INIT_LIST_HEAD(&section->mark_list);
-                       section->mark_count = 0;
-               }
-       } else {
-               chmcerr_set(errno, strerror(errno));
-               chmcerr_msg("section '%s' allocation failed", name);
-       }
-
-       return section;
-
- fail:
-       free(section);
-       return NULL;
-}
-
-void chmc_reset_table_init(struct chmcLzxcResetTable *reset_table)
-{
-       reset_table->version = 2;
-       reset_table->block_count = 0;
-       reset_table->entry_size = 8;
-       reset_table->table_offset = _CHMC_LZXC_RESETTABLE_V1_LEN;
-       reset_table->uncompressed_len = 0;
-       reset_table->compressed_len = 0;
-       reset_table->block_len = 0x8000;
-}
-
-void chmc_control_data_init(struct chmcLzxcControlData *control_data)
-{
-       control_data->size = 6;
-       memcpy(control_data->signature, "LZXC", 4);
-       control_data->version = 2;
-       control_data->resetInterval = 2;
-       control_data->windowSize = 2;
-       control_data->windowsPerReset = 1;
-       control_data->unknown_18 = 0;
-}
-
-void chmc_sections_done(struct chmcFile *chm)
-{
-       int len;
-       int i;
-
-       assert(chm);
-
-       chm->sections = malloc(sizeof(struct chmcSection *) * chm->sections_num);
-       if (chm->sections) {
-               struct chmcSection *section;
-               struct list_head *pos;
-
-               i = 0;
-               len = 4;
-               list_for_each(pos, &chm->sections_list) {
-                       section = list_entry(pos, struct chmcSection, list);
-                       len += 4 + strlen(section->name) * 2;
-                       chm->sections[i++] = section;
-               }
-               chmc_namelist_create(chm, len);
-       } else
-               BUG_ON("FIXME: %s: %d\n", __FILE__, __LINE__);
-}
-
-int chmc_namelist_create(struct chmcFile *chm, int len)
-{
-       UInt16 *namelist;
-
-       namelist = malloc(len);
-       if (namelist) {
-               struct chmcSection *section;
-               int i, j, k, name_len;
-
-               k = 0;
-               namelist[k++] = len >> 1;
-               namelist[k++] = chm->sections_num;
-               for( i=0; i < chm->sections_num; i++ ) {
-                       section = chm->sections[i];
-
-                       name_len = strlen(section->name);
-                       namelist[k++] = name_len;
-                       for( j=0; j < name_len; j++ )
-                               namelist[k++] = section->name[j];
-                       namelist[k++] = 0;
-               }
-               chmc_add_meta(chm, "::DataSpace/NameList", 0, (UChar *)namelist, len);
-       }
-       else
-               return CHMC_ENOMEM;
-
-       return CHMC_NOERR;
-}
-
-struct chmcTreeNode *chmc_add_empty(struct chmcFile *chm, const char *file)
-{
-       assert(chm);
-       return chmc_add_entry(chm, file, 0, 0, NULL, 0, 0);
-}
-
-struct chmcTreeNode *chmc_add_meta(struct chmcFile *chm, const char *metaname,
-                                   int sect_id,
-              UChar *buf, UInt64 len)
-{
-       struct chmcSection *section;
-       struct chmcTreeNode *node;
-
-       assert(chm);
-
-       if (sect_id >= chm->sections_num)
-               return NULL;
-
-       section = chm->sections[sect_id];
-
-       node = chmc_add_entry(chm, metaname, 0, sect_id, buf, section->offset, len);
-
-       if ((node) && (len > 0))
-               section->offset += len;
-
-       return node;
-}
-
-struct chmcTreeNode *chmc_add_entry(struct chmcFile *chm, const char *name,
-                                    UInt16 prefixlen, int sect_id, UChar *buf,
-                                    UInt64 offset, UInt64 len)
-{
-       struct chmcTreeNode *node;
-
-       assert(chm);
-
-       if (sect_id >= (chm->sections_num)) {
-               fprintf(stderr,"sect_id %d >= chm->sections_num %d\n",
-                       sect_id, chm->sections_num);
-               return NULL;
-       }
-
-       node = malloc(sizeof(struct chmcTreeNode));
-       if (node) {
-               node->flags = 0;
-               node->name = strdup( name );
-               node->prefixlen = prefixlen;
-               node->sect_id = sect_id;
-               node->buf = buf;
-               node->offset = offset;
-               node->len = len;
-               list_add_tail(&node->list, &chm->entries_list);
-               chm->entries_num++;
-       }
-       else
-               BUG_ON("FIXME: %s: %d\n", __FILE__, __LINE__);
-
-       return node;
-}
-
-void chmc_term(struct chmcFile *chm)
-{
-       assert(chm);
-       assert(chm->fd > -1);
-
-       free(chm->strings);
-
-       chmc_entries_free(chm);
-       chmc_pmgl_free(chm);
-       chmc_pmgi_free(chm);
-       if (chm->sections)
-               free(chm->sections);
-       chmc_sections_free(chm);
-
-       if (chm->fd != fileno(stdout))
-               close(chm->fd);
-}
-
-void chmc_sections_free(struct chmcFile *chm)
-{
-       struct chmcSection *section;
-       struct list_head *pos, *q;
-
-       assert(chm);
-
-       list_for_each_safe(pos, q, &chm->sections_list) {
-               section = list_entry(pos, struct chmcSection, list);
-               list_del(pos);
-               chmc_section_destroy(section);
-       }
-}
-
-void chmc_section_destroy(struct chmcSection *section)
-{
-       assert(section);
-       assert(section->fd > -1);
-
-       if (strcmp(section->name, "MSCompressed") == 0) {
-               struct list_head *pos, *q;
-               struct chmcResetTableMark *mark;
-
-               list_for_each_safe(pos, q, &section->mark_list) {
-                       mark = list_entry(pos, struct chmcResetTableMark, list);
-                       list_del(pos);
-                       free(mark);
-               }
-       }
-
-       close(section->fd);
-       unlink(section->filename);
-       free(section);
-}
-
-void chmc_pmgi_free(struct chmcFile *chm)
-{
-       struct chmcPmgiChunkNode *node;
-       struct list_head *pos, *q;
-
-       assert(chm);
-
-       list_for_each_safe(pos, q, &chm->pmgi_list) {
-               node = list_entry(pos, struct chmcPmgiChunkNode, list);
-               list_del(pos);
-               chmc_pmgi_destroy(node);
-       }
-}
-
-void chmc_pmgl_free(struct chmcFile *chm)
-{
-       struct chmcPmglChunkNode *node;
-       struct list_head *pos, *q;
-
-       assert(chm);
-
-       list_for_each_safe(pos, q, &chm->pmgl_list) {
-               node = list_entry(pos, struct chmcPmglChunkNode, list);
-               list_del(pos);
-               chmc_pmgl_destroy(node);
-       }
-}
-
-void chmc_entries_free( struct chmcFile *chm )
-{
-       struct chmcTreeNode *node;
-       struct list_head *pos, *q;
-
-       assert(chm);
-
-       list_for_each_safe(pos, q, &chm->entries_list) {
-               node = list_entry(pos, struct chmcTreeNode, list);
-               list_del(pos);
-               chmc_entry_destroy(node);
-       }
-
-       free(chm->sort_entries);
-}
-
-UInt32 chmc_strings_add( struct chmcFile *chm, const char *s)
-{
-       UInt32 len, off;
-
-       /* FIXME null are errors */
-
-       if (!s || *s == '\0')
-               return 0;
-
-       len = strlen(s);
-
-       off = chm->strings_offset;
-
-       if (off + len + 1 < chm->strings_len) {
-
-               memcpy(&chm->strings[off], s, len + 1);
-               chm->strings_offset += len + 1;
-
-       } else {
-               /* realloc strings */
-               /* if the string truncate copy til end of chunk
-                  then re-copy from 0 of new */
-               BUG_ON("FIXME: %s: %d: handle more chunk for strings\n",
-                      __FILE__, __LINE__);
-       }
-
-       return off;
-}
-
-void chmc_entry_destroy( struct chmcTreeNode *node )
-{
-       assert(node);
-       assert(node->name);
-
-       free(node->name);
-       if (node->buf && !(node->flags & CHMC_TNFL_STATIC))
-               free(node->buf);
-       free(node);
-}
-
-struct chmcTreeNode *chmc_add_file(struct chmcFile *chm, const char *filename,
-                                   UInt16 prefixlen, int sect_id, UChar *buf,
-                                   UInt64 len)
-{
-       struct chmcSection *section;
-       struct chmcTreeNode *node;
-
-       assert(chm);
-
-       if (sect_id >= chm->sections_num)
-               return NULL;
-
-       section = chm->sections[sect_id];
-
-       node = chmc_add_entry(chm, filename, prefixlen, sect_id, NULL,
-                             section->offset, len);
-
-       if ((node) && (len > 0))
-               section->offset += len;
-
-       return node;
-}
-
-struct chmcTreeNode *chmc_add_dir(struct chmcFile *chm, const char *dir)
-{
-       assert(chm);
-
-       return chmc_add_entry(chm, dir, 0, 0, NULL, 0, 0);
-}
-
-static inline void *chmc_syscat_mem(void *d, void *s, unsigned long len)
-{
-       memcpy(d, s, len);
-
-       return (char *)d + len;
-}
-
-static void *chmc_syscat_entry(Int16 code, void *d, void *s, Int16 len)
-{
-       d = chmc_syscat_mem(d, &code, 2);
-       d = chmc_syscat_mem(d, &len, 2);
-
-       return chmc_syscat_mem(d, s, len);
-}
-
-/* #define DEFAULT_TOPIC "index.htm" */
-/* #define TITLE "hello world" */
-/* #define LCASEFILE "test" */
-
-int chmc_system_done(struct chmcFile *chm)
-{
-       struct chmcSystem *system;
-       struct chmcSystemInfo *sysinfo;
-       struct chmcIndexHeader *idxhdr;
-       void *sysp, *p;
-
-       assert(chm);
-
-       system = &chm->system;
-       sysinfo = &system->info;
-       idxhdr = &chm->idxhdr;
-
-       // TODO should be set from application
-       //   system->_size +=   (_CHMC_SYS_ENTRY_HDR_LEN + sizeof(UInt32)) /* timestamp */
-       //                    + (_CHMC_SYS_ENTRY_HDR_LEN + sizeof(PACKAGE_STRING)) /* compiler */
-       //                    + (_CHMC_SYS_ENTRY_HDR_LEN + sizeof(UInt32)) /* eof */
-       //                    + (_CHMC_SYS_ENTRY_HDR_LEN + sizeof(DEFAULT_TOPIC))
-       //                    + (_CHMC_SYS_ENTRY_HDR_LEN + sizeof(TITLE))
-       //                    + 32;
-
-       sysp = malloc(16384);
-       if (sysp) {
-               UInt32 val;
-               UInt16 code, len;
-               const char *entry_val;
-
-               p = chmc_syscat_mem(sysp, &system->version, sizeof(system->version));
-
-               val = 0;
-               p = chmc_syscat_entry(SIEC_TIMESTAMP, p, &val, sizeof(val));
-               p = chmc_syscat_entry(SIEC_COMPVER, p,
-                                     /*"HHA Version 4.74.8702"*/
-                                     PACKAGE_STRING,
-                                     sizeof(PACKAGE_STRING)
-                                     /*strlen("HHA Version 4.74.8702")+1*/);
-               p = chmc_syscat_entry(SIEC_SYSINFO, p,
-                                     sysinfo, sizeof(struct chmcSystemInfo));
-
-               if (chm->config != NULL && chm->config->deftopic != NULL)
-                       entry_val = chm->config->deftopic;
-               else
-                       entry_val = "index.htm";
-               p = chmc_syscat_entry(SIEC_DEFTOPIC, p, (void *)entry_val,
-                                     strlen(entry_val)+1);
-
-               if (chm->config != NULL && chm->config->title != NULL)
-                       entry_val = chm->config->title;
-               else
-                       entry_val = "untitled";
-               p = chmc_syscat_entry(SIEC_TITLE, p, (void *)entry_val,
-                                     strlen(entry_val)+1);
-               //       p = chmc_syscat_entry(SIEC_DEFFONT, p, &val, sizeof(val));
-               p = chmc_syscat_entry(SIEC_LCASEFILE, p, "siec_lcasefile",
-                                     strlen("siec_lcasefile")+1);
-               p = chmc_syscat_entry(SIEC_DEFWINDOW, p,
-                                     "MsdnHelp", strlen("MsdnHelp")+1);
-
-               val = 0;
-               p = chmc_syscat_entry(SIEC_NUMOFINFOT, p, &val, sizeof(val));
-
-               p = chmc_syscat_entry(SIEC_IDXHDR, p,
-                                     idxhdr, sizeof(struct chmcIndexHeader));
-
-
-               val = 0;
-               p = chmc_syscat_entry(SIEC_INFOCHKSUM, p, &val, sizeof(val));
-
-               system->_size = (char *)p - (char *)sysp;
-               chmc_add_meta(chm, "/#SYSTEM", 0, sysp, system->_size);
-               return CHMC_NOERR;
-       }
-
-       chmcerr_set(CHMC_ENOMEM, "system done: malloc %d bytes",
-                   system->_size);
-
-       return CHMC_ENOMEM;
-}
-
-int chmc_tree_done( struct chmcFile *chm )
-{
-       struct chmcItsfHeader *itsf;
-       struct chmcSect0 *sect0;
-       struct chmcItspHeader *itsp;
-       struct chmcTreeNode *ctrl;
-       UInt32 str_index;
-       const char *val;
-
-       assert(chm);
-
-       itsf = &chm->itsf;
-       sect0 = &chm->sect0;
-       itsp = &chm->itsp;
-
-       chmc_add_dir(chm, "/");
-
-       ctrl = chmc_add_meta(chm, "::DataSpace/Storage/MSCompressed/Transform/List",
-                            0, (UChar *)chmc_transform_list,
-                            sizeof(chmc_transform_list));
-       if (ctrl)
-               ctrl->flags |= CHMC_TNFL_STATIC;
-
-       chmc_system_done(chm);
-
-       if (chm->config != NULL && chm->config->deftopic != NULL)
-               val = chm->config->deftopic;
-       else
-               val = "index.htm";
-
-       str_index = chmc_strings_add(chm, val);
-
-#if 0
-       // FIXME just a test
-       {
-               UChar *p;
-               int len;
-               struct chmcTopicEntry topicEntry;
-               //     struct chmcUrlStrEntry urlStrEntry;
-
-               p = malloc(4096);
-               if (p) {
-                       memset(p, 0, 4096);
-                       len = 0;
-
-                       topicEntry.tocidx_offset = 4096;
-                       topicEntry.strings_offset = -1;
-                       topicEntry.urltbl_offset = 0;
-                       topicEntry.in_content = 6;
-                       topicEntry.unknown = 0;
-
-                       memcpy(p, &topicEntry, sizeof(struct chmcTopicEntry));
-                       len += sizeof(struct chmcTopicEntry);
-
-                       chm->idxhdr.num_of_topic++;
-
-                       chmc_add_meta(chm, "/#TOPICS", 1, (UChar *)p, len);
-               } else
-                       BUG_ON("FIXME: %s: %d\n", __FILE__, __LINE__);
-       }
-#endif
-
-       ctrl = chmc_add_meta(chm, "/#IDXHDR", 1, (void *)&chm->idxhdr,
-                            sizeof(struct chmcIndexHeader));
-       if (ctrl)
-               ctrl->flags |= CHMC_TNFL_STATIC;
-
-       {
-               UInt32 *p;
-               p = malloc(8+196);
-               if (p) {
-                       const char *val;
-                       memset(p+2, 0, 196);
-
-                       p[0] = 1;
-                       p[1] = 196;
-
-                       p[2+0] = 196;
-                       //       p[2+2] = 1;
-                       //       p[2+3] = 0x00000532;
-                       //       p[2+4] = 0x00062520;
-
-                       //       p[2+8] = 86;
-                       //       p[2+9] = 51;
-                       //       p[2+10] = 872;
-                       //       p[2+11] = 558;
-
-                       //       p[2+19] = 220;
-
-                       //       p[2+27] = 0x00000041;
-                       //       p[2+28] = 14462;
-
-                       if (chm->config != NULL && chm->config->title != NULL)
-                               val = chm->config->title;
-                       else
-                               val = "untitled";
-                       p[2+5] = chmc_strings_add(chm, val);
-
-                       if (chm->config != NULL && chm->config->hhc != NULL)
-                               val = chm->config->hhc;
-                       else
-                               val = "toc.hhc";
-                       p[2+24] = chmc_strings_add(chm, val);
-
-                       if (chm->config != NULL && chm->config->hhk != NULL)
-                               val = chm->config->hhc;
-                       else
-                               val = "toc.hhk";
-                       p[2+25] = chmc_strings_add(chm, val);
-                       p[2+26] = str_index;
-
-                       chmc_add_meta(chm, "/#WINDOWS", 1, (UChar *)p, 8+196);
-               } else
-                       BUG_ON("FIXME: %s: %d\n", __FILE__, __LINE__);
-       }
-
-       ctrl = chmc_add_meta(chm, "/#STRINGS", 1, (void *)chm->strings,
-                            chm->strings_len);
-       if (ctrl)
-               ctrl->flags |= CHMC_TNFL_STATIC;
-
-#if 0
-       // FIXME just a test
-       {
-               UChar *p;
-               int len;
-               struct chmcUrlStrEntry urlStrEntry;
-
-               urlStrEntry.url_offset = 0;
-               urlStrEntry.framename_offset = 0;
-
-               p = malloc(4096);
-               if (p) {
-                       memset(p, 0, 4096);
-                       *p = 0x42;
-                       len = 1;
-
-                       memcpy(p + len, &urlStrEntry, sizeof(struct chmcUrlStrEntry));
-                       len += sizeof(struct chmcUrlStrEntry);
-                       len += sprintf(p + len, "index.htm" ) + 1;
-
-                       memcpy(p + len, &urlStrEntry, sizeof(struct chmcUrlStrEntry));
-                       len += sizeof(struct chmcUrlStrEntry);
-                       len += sprintf(p + len, "test.htm" ) + 1;
-
-                       chmc_add_meta(chm, "/#URLSTR", 1, (UChar *)p, len);
-               } else
-                       BUG_ON("FIXME: %s: %d\n", __FILE__, __LINE__);
-       }
-#endif
-
-       //   chmc_add_entry(chm, "/#URLTBL", 0, 1, NULL, 0, 0);
-       //   chmc_add_entry(chm, "/#TOPICS", 0, 1, NULL, 0, 0);
-
-       // NOTE NOTE NOTE add any meta compressed before crunch ;-)
-
-       chmc_crunch_lzx(chm, 1);
-
-       chmc_control_data_done(chm);
-       chmc_reset_table_done(chm);
-
-       chmc_add_empty(chm, "/#ITBITS");
-
-       // NOTE in this implementation compressed Content should be the last file
-       //      added to section 0
-
-       chmc_add_meta(chm, "::DataSpace/Storage/MSCompressed/Content", 0, NULL,
-                     chm->sections[1]->offset);
-
-       chmc_entries_qsort(chm);
-       chmc_uncompressed_done(chm);
-       chmc_pmgl_done(chm);
-
-       chmc_pmgi_done(chm);
-
-       itsf->dir_len =     _CHMC_ITSP_V1_LEN
-               + (_CHMC_CHUNK_LEN * itsp->num_blocks);
-
-       itsf->data_offset = _CHMC_ITSF_V3_LEN
-               + _CHMC_SECT0_LEN
-               + _CHMC_ITSP_V1_LEN
-               + (_CHMC_CHUNK_LEN * itsp->num_blocks);
-
-       sect0->file_len +=  _CHMC_CHUNK_LEN * itsp->num_blocks;
-
-       chmc_write(chm);
-
-       {
-               struct chmcSection *section;
-               struct list_head *pos;
-               UChar buf[4096];
-
-               list_for_each(pos, &chm->sections_list) {
-                       section = list_entry(pos, struct chmcSection, list);
-                       chmc_appendfile(chm, section->filename, buf, 4096);
-               }
-       }
-
-       return CHMC_NOERR;
-}
-
-int chmc_crunch_lzx(struct chmcFile *chm, int sect_id)
-{
-       struct chmcLzxInfo lzx_info;
-
-       lzx_data *lzxd;
-       int subd_ok = 1;
-       int do_reset = 1;
-       int block_size;
-       lzx_results lzxr;
-       int wsize_code = 16;
-
-       assert(chm);
-
-       if ((wsize_code < 15) || (wsize_code > 21)) {
-               fprintf(stderr, "window size must be between 15 and 21 inclusive\n");
-               return CHMC_EINVAL;
-       }
-
-       lzx_info.chm = chm;
-       lzx_info.section = chm->sections[sect_id];
-       lzx_info.done = 0;
-       lzx_info.todo = lzx_info.section->offset;
-       lzx_info.pos = chm->entries_list.next;
-       lzx_info.error = 0;
-       lzx_info.eof = 0;
-
-       lzx_info.fd = -1;
-       lzx_info.fd_offset = 0;
-
-       chmc_compressed_add_mark(lzx_info.chm, 0);
-       lzx_info.section->reset_table_header.block_count++;
-
-       /* undocumented fact, according to Caie --
-          block size cannot exceed window size.  (why not?) */
-       /* The block size must not be larger than the window size.
-          While the compressor will create apparently-valid LZX files
-          if this restriction is violated, some decompressors
-          will not handle them. */
-
-       block_size = 1 << wsize_code;
-
-       //  lzx_info.section->control_data.windowSize = wsize_code;
-       //  lzx_info.section->control_data.windowsPerReset = block_size;
-
-       lzx_init(&lzxd, wsize_code,
-                _lzx_get_bytes, &lzx_info, _lzx_at_eof,
-                _lzx_put_bytes, &lzx_info,
-                _lzx_mark_frame, &lzx_info);
-
-       while(! _lzx_at_eof(&lzx_info)) {
-               if (do_reset)
-                       lzx_reset(lzxd);
-               lzx_compress_block(lzxd, block_size, subd_ok);
-       }
-       lzx_finish(lzxd, &lzxr);
-
-       return CHMC_NOERR;
-}
-
-static int _lzx_at_eof(void *arg)
-{
-       struct chmcLzxInfo *lzx_info = (struct chmcLzxInfo *)arg;
-
-       return lzx_info->error || lzx_info->done >= lzx_info->todo || lzx_info->eof;
-}
-
-static int _lzx_put_bytes(void *arg, int n, void *buf)
-{
-       struct chmcLzxInfo *lzx_info = (struct chmcLzxInfo *)arg;
-       struct chmcSect0 *sect0 = &lzx_info->chm->sect0;
-       int wx;
-       static int counter = 0;
-
-       counter += n;
-       wx = write(lzx_info->section->fd, buf, n);
-       sect0->file_len += wx;
-       lzx_info->section->len += wx;
-
-       return wx;
-}
-
-static void _lzx_mark_frame(void *arg, uint32_t uncomp, uint32_t comp)
-{
-       struct chmcLzxInfo *lzx_info = (struct chmcLzxInfo *)arg;
-       struct chmcSection *section = lzx_info->chm->sections[1];
-
-       UInt64 compressed;
-
-       chmc_dump( "Aligned data at %d(in compressed stream, %d) (%lu/%lu)\n",
-                  uncomp, comp, (unsigned long)lzx_info->done, (unsigned long)lzx_info->todo );
-
-       compressed = comp;
-
-       section->reset_table_header.block_count++;
-
-       chmc_compressed_add_mark( lzx_info->chm, compressed );
-
-       section->reset_table_header.uncompressed_len = uncomp;
-       section->reset_table_header.compressed_len = comp;
-}
-
-static int _lzx_get_bytes(void *arg, int n, void *buf)
-{
-       struct chmcLzxInfo *lzx_info = (struct chmcLzxInfo *)arg;
-       struct chmcFile *chm = lzx_info->chm;
-       struct chmcTreeNode *node;
-
-       int todo;
-       int done;
-       int toread;
-       int rx;
-
-       todo = n;
-       done = 0;
-
-       // compression state machine
-       // lzx compressor ask for block input bytes
-       // need to keep current entry file and offset trought blocks
-       // until last entry
-       while (todo) {
-               // end of entries reached?
-               if (lzx_info->pos == &chm->entries_list) {
-                       lzx_info->eof = 1;
-                       break;
-               }
-
-               node = list_entry( lzx_info->pos, struct chmcTreeNode, list );
-
-               // skip empty files and directories
-               if (node->len == 0
-                  || strcmp("MSCompressed", chm->sections[node->sect_id]->name)) {
-                       lzx_info->pos = lzx_info->pos->next;
-                       continue;
-               }
-               else
-                       if (node->buf) {
-                               // have len and buffer, it's mallocated not file
-                       }
-                       else
-                               if (lzx_info->fd == -1) {
-                                       // open file if it isn't
-                                       lzx_info->fd = open(node->name, O_RDONLY | O_BINARY);
-                                       if (lzx_info->fd < 0) {
-                                               chmc_error("%s: %d: error %d: '%s' %s\n",
-                                                          __FILE__, __LINE__,
-                                                          errno, node->name, strerror(errno));
-                                               lzx_info->error = 1;
-                                               break;
-                                       }
-                               }
-
-               // read till the end of the file or till the lzx buffer is filled
-               toread = node->len - lzx_info->fd_offset;
-               if (toread > todo)
-                       toread = todo;
-
-               if (toread <= 0)
-                       continue;
-
-               // read input
-               if (node->buf) {
-                       memcpy((char *)buf + (n - todo), &node->buf[lzx_info->fd_offset], toread);
-                       rx = toread;
-               }
-               else
-                       {
-                               rx = read(lzx_info->fd, (char *)buf + (n - todo), toread);
-                               if (rx <= 0) {
-                                       int temp = errno;
-                                       chmc_error("read error %s \n", strerror(temp));
-                                       lzx_info->error = 2;
-                                       break;
-                               }
-                       }
-
-               todo -= rx;
-               lzx_info->fd_offset += rx;
-               done += rx;
-               lzx_info->done += rx;
-
-               // end of current file reached, goto next entry
-               if (lzx_info->fd_offset == node->len) {
-                       if (lzx_info->fd > -1)
-                               close(lzx_info->fd);
-                       lzx_info->fd = -1;
-                       lzx_info->fd_offset = 0;
-                       lzx_info->pos = lzx_info->pos->next;
-               }
-       }
-
-       return done;
-}
-
-int chmc_compressed_add_mark(struct chmcFile *chm, UInt64 at)
-{
-       struct chmcSection *section;
-       struct chmcResetTableMark *mark;
-
-       assert(chm);
-
-       section = chm->sections[1];
-
-       mark = malloc(_CHMC_RSTTBL_MARK);
-       if (mark) {
-               mark->at = at;
-               chmc_dump("[%d] at: %jd\n", section->mark_count, at);
-               list_add_tail(&mark->list, &section->mark_list);
-               section->mark_count++;
-               return CHMC_NOERR;
-       }
-
-       return CHMC_ENOMEM;
-}
-
-int chmc_control_data_done(struct chmcFile *chm)
-{
-       struct chmcTreeNode *ctrl;
-
-       ctrl = chmc_add_meta(chm, "::DataSpace/Storage/MSCompressed/ControlData",
-                            0, (UChar *)&chm->sections[1]->control_data,
-                            _CHMC_LZXC_V2_LEN);
-
-       if (ctrl) {
-               ctrl->flags |= CHMC_TNFL_STATIC;
-               return CHMC_NOERR;
-       }
-
-       return CHMC_ENOMEM;
-}
-
-int chmc_reset_table_done(struct chmcFile *chm)
-{
-       struct chmcSection *section;
-       struct chmcLzxcResetTable *reset_table;
-       struct list_head *pos;
-       struct chmcResetTableMark *mark;
-
-       UInt64 *at;
-       int i, len;
-
-       section = chm->sections[1];
-
-       len = _CHMC_LZXC_RESETTABLE_V1_LEN + (section->mark_count * sizeof(UInt64));
-
-       reset_table = malloc(len);
-
-       if (reset_table) {
-               memcpy(reset_table, &section->reset_table_header,
-                      _CHMC_LZXC_RESETTABLE_V1_LEN);
-               at = (void *)((char *)reset_table + _CHMC_LZXC_RESETTABLE_V1_LEN);
-
-               i = 0;
-               list_for_each(pos, &section->mark_list) {
-                       mark = list_entry(pos, struct chmcResetTableMark, list);
-                       at[i++] = mark->at;
-               }
-
-               chmc_add_dir(chm, "::DataSpace/Storage/MSCompressed/Transform/"
-                            "{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/");
-               chmc_add_meta(chm, "::DataSpace/Storage/MSCompressed/Transform/"
-                             "{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}"
-                             "/InstanceData/ResetTable",
-                             0, (UChar *)reset_table, len);
-
-               { // TODO FIXME do better
-                       UInt64 *uncompressed_len = malloc(8);
-                       if (uncompressed_len) {
-                               *uncompressed_len = reset_table->uncompressed_len;
-                               chmc_add_meta(chm, "::DataSpace/Storage/MSCompressed/SpanInfo",
-                                             0, (UChar *)uncompressed_len, 8);
-                       }
-               }
-
-               return CHMC_NOERR;
-       }
-
-       return CHMC_ENOMEM;
-}
-
-void chmc_entries_qsort(struct chmcFile *chm)
-{
-       struct chmcTreeNode *node;
-       struct list_head *pos;
-       int i;
-
-       assert(chm);
-
-       chm->sort_entries = malloc(sizeof(struct chmcTreeNode *)
-                                  * chm->entries_num);
-
-       i = 0;
-       list_for_each(pos, &chm->entries_list) {
-               node = list_entry(pos, struct chmcTreeNode, list);
-               chm->sort_entries[i++] = node;
-       }
-
-       qsort(chm->sort_entries, chm->entries_num, sizeof(struct chmcTreeNode *),
-             _entry_cmp);
-}
-
-static int _entry_cmp(const void *pva, const void *pvb)
-{
-       const struct chmcTreeNode * const *pa = pva;
-       const struct chmcTreeNode * const *pb = pvb;
-       const struct chmcTreeNode *a = *pa, *b = *pb;
-
-       return strcmp( &a->name[a->prefixlen], &b->name[b->prefixlen] );
-}
-
-int chmc_uncompressed_done(struct chmcFile *chm)
-{
-       struct chmcSect0 *sect0 = &chm->sect0;
-       struct chmcTreeNode *node;
-       struct list_head *pos;
-       int wx;
-
-       list_for_each(pos, &chm->entries_list) {
-               node = list_entry( pos, struct chmcTreeNode, list );
-
-               if (strcmp( "MSCompressed", chm->sections[node->sect_id]->name ) == 0)
-                       continue;
-
-               if ((node->buf) && (node->len > 0)) {
-                       wx = write(chm->sections[node->sect_id]->fd, node->buf, node->len);
-                       sect0->file_len += wx;
-               }
-       }
-
-       return CHMC_NOERR;
-}
-
-void chmc_pmgl_done(struct chmcFile *chm)
-{
-       struct chmcTreeNode *entry;
-       int i;
-
-       assert(chm);
-
-       for(i=0; i < chm->entries_num; i++) {
-               entry = chm->sort_entries[i];
-               chmc_pmgl_add_entry(chm, entry);
-       }
-}
-
-int chmc_pmgl_add_entry(struct chmcFile *chm, struct chmcTreeNode *entry)
-{
-       struct chmcPmglChunkNode *pmgl;
-       struct chmcPmglChunk *chunk;
-       struct chmcSection *section;
-       struct chmcItspHeader *itsp = &chm->itsp;
-
-       UChar *p;
-       UInt16 *idx;
-       int name_len;
-       int outlen;
-       int should_idx, idx_intlv;
-       int free;
-
-       assert(chm);
-       assert(entry);
-
-       // check section bound
-       section = chmc_section_lookup(chm, entry->sect_id);
-       if (!section)
-               chmcerr_set_return(CHMC_ENOMEM, "section %d lookup failed: ",
-                                  entry->sect_id);
-
-       // check chunk space for new entry
-       name_len = strlen(&entry->name[entry->prefixlen]);
-
-       outlen = chmc_encint_len(name_len);
-       outlen += name_len;
-       outlen += chmc_encint_len(entry->sect_id);
-       outlen += chmc_encint_len(entry->offset);
-       outlen += chmc_encint_len(entry->len);
-
-       // look for current pmgl chunk, create if doesn't exist
-       if (!chm->pmgl_last) {
-               pmgl = chmc_pmgl_create();
-               if (pmgl)
-                       chmc_pmgl_add(chm, pmgl);
-               else
-                       chmcerr_set_return(CHMC_ENOMEM, "pmgl chunk: ");
-       }
-       else
-               pmgl = chm->pmgl_last;
-
-       do {
-
-               chunk = &chm->pmgl_last->chunk;
-
-               idx_intlv = 1 + ( 1 << itsp->blockidx_intvl );
-               should_idx = ( ( chunk->entries_count > 0 )
-                              && ! ( ( chunk->entries_count + 1 ) % idx_intlv )
-                              ? 2 : 0 );
-
-               free = sizeof(chunk->data) - pmgl->data_len - pmgl->index_len
-                       - should_idx;
-
-               // current(last) chunk doesn't have enough room? force new one
-               if (outlen + should_idx > free) {
-                       //chm->pmgl_last = NULL;
-                       pmgl = chmc_pmgl_create();
-                       if ( pmgl )
-                               chmc_pmgl_add(chm, pmgl);
-                       else
-                               chmcerr_set_return(CHMC_ENOMEM, "pmgl chunk: ");
-
-                       continue;
-               }
-
-               p = (void *)&chunk->data[pmgl->data_len];
-
-               if (should_idx) {
-                       idx = (void *)((char *)&chunk->data[CHMC_PMGL_DATA_LEN] - pmgl->index_len);
-                       *idx = (char *)p - (char *)&chunk->data;
-               }
-
-               p += chmc_encint(name_len, p);
-               memcpy(p, &entry->name[entry->prefixlen], name_len);
-               p += name_len;
-               p += chmc_encint(entry->sect_id, p);
-               p += chmc_encint(entry->offset, p);
-               p += chmc_encint(entry->len, p);
-
-               pmgl->data_len += outlen;
-               pmgl->index_len += should_idx;
-
-               chunk->entries_count++;
-               chunk->header.free_space -= outlen;
-               break;
-
-       } while (1);
-
-       return CHMC_NOERR;
-}
-
-struct chmcSection *chmc_section_lookup(struct chmcFile *chm, int id)
-{
-       struct chmcSection *current;
-       struct list_head *pos;
-       int i;
-
-       assert(chm);
-
-       i = 0;
-       list_for_each(pos, &chm->sections_list) {
-               current = list_entry(pos, struct chmcSection, list);
-               if (i == id)
-                       return current;
-               i++;
-       }
-
-       return NULL;
-}
-
-struct chmcPmglChunkNode *chmc_pmgl_create(void)
-{
-       struct chmcPmglChunkNode *node;
-
-       node = malloc(sizeof(struct chmcPmglChunkNode));
-       if (node)
-               chmc_pmgl_init(node);
-
-       return node;
-}
-
-void chmc_pmgl_init(struct chmcPmglChunkNode *node)
-{
-       struct chmcPmglChunk *chunk;
-
-       assert(node);
-
-       node->data_len = 0;
-       node->index_len = 0;
-
-       chunk = &node->chunk;
-
-       memcpy(chunk->header.signature, "PMGL", 4);
-
-       // FIXME check it is the right len
-       chunk->header.free_space = CHMC_PMGL_DATA_LEN + 2;
-       chunk->header.unknown_0008 = 0;
-       chunk->header.block_prev = -1;
-       chunk->header.block_next = -1;
-
-       memset(chunk->data, 0, CHMC_PMGL_DATA_LEN);
-}
-
-void chmc_pmgi_init(struct chmcPmgiChunkNode *node)
-{
-       struct chmcPmgiChunk *chunk;
-
-       assert(node);
-
-       node->data_len = 0;
-       node->index_len = 0;
-
-       chunk = &node->chunk;
-
-       memcpy(chunk->header.signature, "PMGI", 4);
-
-       // FIXME check it is the right len
-       chunk->header.free_space = CHMC_PMGI_DATA_LEN + 2;
-       //  chunk->header.unknown_0008 = 0;
-       //  chunk->header.block_prev = -1;
-       //  chunk->header.block_next = -1;
-
-       memset(chunk->data, 0, CHMC_PMGI_DATA_LEN);
-}
-
-
-
-struct chmcPmgiChunkNode *chmc_pmgi_create(void)
-{
-       struct chmcPmgiChunkNode *node;
-
-       node = malloc(sizeof(struct chmcPmgiChunkNode));
-       if (node)
-               chmc_pmgi_init(node);
-
-       return node;
-}
-
-void chmc_pmgl_destroy(struct chmcPmglChunkNode *node)
-{
-       assert(node);
-       free(node);
-}
-
-void chmc_pmgi_destroy(struct chmcPmgiChunkNode *node)
-{
-       assert(node);
-       free(node);
-}
-
-void chmc_pmgl_add(struct chmcFile *chm, struct chmcPmglChunkNode *pmgl)
-{
-       struct chmcItspHeader *itsp = &chm->itsp;
-       struct chmcPmglHeader *hdr;
-
-       assert(chm);
-       assert(pmgl);
-
-       list_add_tail(&pmgl->list, &chm->pmgl_list);
-
-       itsp->index_last = itsp->num_blocks;
-
-       hdr = &pmgl->chunk.header;
-       hdr->block_prev = itsp->num_blocks - 1;
-
-       if (chm->pmgl_last) {
-               hdr = &chm->pmgl_last->chunk.header;
-               hdr->block_next = itsp->num_blocks;
-       }
-
-       itsp->num_blocks++;
-
-       chm->pmgl_last = pmgl;
-}
-
-int chmc_pmgi_done(struct chmcFile *chm)
-{
-       struct chmcItspHeader *itsp = &chm->itsp;
-       struct chmcPmglChunkNode *pmgl;
-       struct list_head *pos;
-
-       int i, j;
-       char name[256]; //FIXME use malloc
-       UInt32 name_len;
-
-       assert(chm);
-
-       // only one pml, omitted pmgi
-       if (itsp->num_blocks == 1) {
-               itsp->index_depth = 1;
-               itsp->index_root = -1;
-               itsp->index_last = 0;
-               return CHMC_NOERR;
-       }
-
-       itsp->index_root = itsp->num_blocks;
-
-       i = 0;
-       list_for_each(pos, &chm->pmgl_list) {
-               pmgl = list_entry(pos, struct chmcPmglChunkNode, list);
-               j = chmc_decint(&pmgl->chunk.data[0], &name_len);
-               if (name_len <= 255) {
-                       memcpy(name, &pmgl->chunk.data[j], name_len);
-                       name[name_len] = '\0';
-                       chmc_pmgi_add_entry(chm, name, i);
-               }
-               else
-                       BUG_ON("name_len >= 255(%lu) %.*s\n", (unsigned long)name_len, 255,
-                              &pmgl->chunk.data[j]);
-               i++;
-       }
-
-       return CHMC_NOERR;
-}
-
-int chmc_pmgi_add_entry(struct chmcFile *chm, const char *name, int pmgl_id)
-{
-       struct chmcPmgiChunkNode *pmgi;
-       struct chmcPmgiChunk *chunk;
-       struct chmcItspHeader *itsp = &chm->itsp;
-
-       UChar *p;
-       UInt16 *idx;
-       int name_len;
-       int outlen;
-       int should_idx, idx_intlv;
-       int free;
-
-       assert(chm);
-
-       // check chunk space for new entry
-       name_len = strlen(name);
-
-       outlen = chmc_encint_len(name_len);
-       outlen += name_len;
-       outlen += chmc_encint_len(pmgl_id);
-
-       // look for current pmgi chunk, create if doesn't exist
-       if (!chm->pmgi_last) {
-               pmgi = chmc_pmgi_create();
-               if (pmgi)
-                       chmc_pmgi_add(chm, pmgi);
-               else
-                       chmcerr_set_return(CHMC_ENOMEM, "pmgi chunk: ");
-       }
-       else
-               pmgi = chm->pmgi_last;
-
-       do {
-
-               chunk = &chm->pmgi_last->chunk;
-
-               idx_intlv = 1 + ( 1 << itsp->blockidx_intvl );
-               should_idx = ( ( chunk->entries_count > 0 )
-                              && ! ( ( chunk->entries_count + 1 ) % idx_intlv )
-                              ? 2 : 0 );
-
-               free = sizeof(chunk->data) - pmgi->data_len -
-                       pmgi->index_len - should_idx;
-
-               // current(last) chunk doesn't have enough room? force new one
-               if (outlen + should_idx > free) {
-                       pmgi = chmc_pmgi_create();
-                       if (pmgi)
-                               chmc_pmgi_add(chm, pmgi);
-                       else
-                               chmcerr_set_return(CHMC_ENOMEM, "pmgi chunk: ");
-
-                       continue;
-               }
-
-               p = (void *)&chunk->data[pmgi->data_len];
-
-               if (should_idx) {
-                       idx = (void *)((char *)&chunk->data[CHMC_PMGI_DATA_LEN] - pmgi->index_len);
-                       *idx = (char *)p - (char *)&chunk->data;
-               }
-
-               p += chmc_encint(name_len, p);
-               memcpy(p, name, name_len);
-               p += name_len;
-               p += chmc_encint(pmgl_id, p);
-
-               pmgi->data_len += outlen;
-               pmgi->index_len += should_idx;
-
-               chunk->entries_count++;
-               chunk->header.free_space -= outlen;
-               break;
-
-       } while (1);
-
-       return CHMC_NOERR;
-}
-
-void chmc_pmgi_add(struct chmcFile *chm, struct chmcPmgiChunkNode *pmgi)
-{
-       struct chmcItspHeader *itsp = &chm->itsp;
-
-       assert(chm);
-       assert(pmgi);
-
-       list_add_tail(&pmgi->list, &chm->pmgi_list);
-       itsp->num_blocks++;
-
-       chm->pmgi_last = pmgi;
-}
-
-int chmc_write(struct chmcFile *chm)
-{
-       struct chmcItsfHeader *itsf = &chm->itsf;
-       struct chmcSect0 *sect0 = &chm->sect0;
-       struct chmcItspHeader *itsp = &chm->itsp;
-
-       struct chmcPmglChunkNode *pmgl;
-       struct chmcPmgiChunkNode *pmgi;
-       struct list_head *pos;
-
-       assert(chm);
-
-       chmc_dump("write itsf %d\n", _CHMC_ITSF_V3_LEN);
-       write(chm->fd, itsf, _CHMC_ITSF_V3_LEN);
-       chmc_dump("write sect0 %d\n", _CHMC_SECT0_LEN);
-       write(chm->fd, sect0, _CHMC_SECT0_LEN);
-       chmc_dump("write itsp %d\n", _CHMC_ITSP_V1_LEN);
-       write(chm->fd, itsp, _CHMC_ITSP_V1_LEN);
-
-       list_for_each(pos, &chm->pmgl_list) {
-               pmgl = list_entry(pos, struct chmcPmglChunkNode, list);
-               chmc_dump("write pmgl %d\n", _CHMC_CHUNK_LEN);
-               write(chm->fd, &pmgl->chunk, _CHMC_CHUNK_LEN);
-       }
-
-       chmc_dump("itsp->num_blocks %d", itsp->num_blocks);
-       if (itsp->num_blocks > 1) {
-               list_for_each( pos, &chm->pmgi_list ) {
-                       pmgi = list_entry(pos, struct chmcPmgiChunkNode, list);
-                       chmc_dump("write pmgi %d\n", _CHMC_CHUNK_LEN);
-                       write(chm->fd, &pmgi->chunk, _CHMC_CHUNK_LEN);
-               }
-       }
-
-       return CHMC_NOERR;
-}
-
-int chmc_appendfile(struct chmcFile *chm, const char *filename, void *buf,
-                size_t size )
-{
-       struct stat statbuf;
-       int in;
-       off_t todo, toread;
-       int rx;
-
-       if (stat(filename, &statbuf) < 0)
-               return errno;
-
-       in = open(filename, O_RDONLY | O_BINARY);
-       if (in >= 0) {
-               todo = statbuf.st_size;
-
-               while (todo) {
-                       toread = size;
-                       if (toread > todo)
-                               toread = todo;
-
-                       rx = read(in, buf, toread);
-                       if (rx > 0) {
-                               write(chm->fd, buf, rx);
-                               todo -= rx;
-                       }
-               }
-
-               close(in);
-       }
-       else
-               BUG_ON("open %s\n", filename);
-
-       return CHMC_NOERR;
-}