static void chmfile_windows_info(struct chmFile *cfd, ChmFile *chmfile) { struct chmUnitInfo ui; unsigned char buffer[4096]; size_t size = 0; u_int32_t entries, entry_size; u_int32_t hhc, hhk, title, home; if (chm_resolve_object(cfd, "/#WINDOWS", &ui) != CHM_RESOLVE_SUCCESS) return; size = chm_retrieve_object(cfd, &ui, buffer, 0L, 8); if (size < 8) return; entries = get_dword(buffer); if (entries < 1) return; entry_size = get_dword(buffer + 4); size = chm_retrieve_object(cfd, &ui, buffer, 8L, entry_size); if (size < entry_size) return; hhc = get_dword(buffer + 0x60); hhk = get_dword(buffer + 0x64); home = get_dword(buffer + 0x68); title = get_dword(buffer + 0x14); if (chm_resolve_object(cfd, "/#STRINGS", &ui) != CHM_RESOLVE_SUCCESS) return; size = chm_retrieve_object(cfd, &ui, buffer, 0L, 4096); if (!size) return; if (chmfile->hhc == NULL && hhc) chmfile->hhc = g_strdup_printf("/%s", buffer + hhc); if (chmfile->hhk == NULL && hhk) chmfile->hhk = g_strdup_printf("/%s", buffer + hhk); if (chmfile->home == NULL && home) chmfile->home = g_strdup_printf("/%s", buffer + home); if (chmfile->title == NULL && title) chmfile->title = g_strdup((char *)buffer + title); }
unsigned char *ChmDoc::GetData(const char *fileName, size_t *lenOut) { ScopedMem<char> fileNameTmp; if (!str::StartsWith(fileName, "/")) { fileNameTmp.Set(str::Join("/", fileName)); fileName = fileNameTmp; } else if (str::StartsWith(fileName, "///")) { fileName += 2; } struct chmUnitInfo info; int res = chm_resolve_object(chmHandle, fileName, &info); if (CHM_RESOLVE_SUCCESS != res) return NULL; size_t len = (size_t)info.length; if (len > 128 * 1024 * 1024) { // don't allow anything above 128 MB return NULL; } // +1 for 0 terminator for C string compatibility ScopedMem<unsigned char> data((unsigned char *)malloc(len + 1)); if (!data) return NULL; if (!chm_retrieve_object(chmHandle, &info, data.Get(), 0, len)) return NULL; data[len] = '\0'; if (lenOut) *lenOut = len; return data.StealData(); }
static HRESULT WINAPI ITSS_IStorageImpl_OpenStream( IStorage* iface, LPCOLESTR pwcsName, void* reserved1, DWORD grfMode, DWORD reserved2, IStream** ppstm) { ITSS_IStorageImpl *This = impl_from_IStorage(iface); IStream_Impl *stm; DWORD len; struct chmUnitInfo ui; int r; WCHAR *path, *p; TRACE("%p %s %p %u %u %p\n", This, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm ); len = strlenW( This->dir ) + strlenW( pwcsName ) + 1; path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); strcpyW( path, This->dir ); if( pwcsName[0] == '/' || pwcsName[0] == '\\' ) { p = &path[strlenW( path ) - 1]; while( ( path <= p ) && ( *p == '/' ) ) *p-- = 0; } strcatW( path, pwcsName ); for(p=path; *p; p++) { if(*p == '\\') *p = '/'; } if(*--p == '/') *p = 0; TRACE("Resolving %s\n", debugstr_w(path)); r = chm_resolve_object(This->chmfile, path, &ui); HeapFree( GetProcessHeap(), 0, path ); if( r != CHM_RESOLVE_SUCCESS ) { WARN("Could not resolve object\n"); return STG_E_FILENOTFOUND; } stm = ITSS_create_stream( This, &ui ); if( !stm ) return E_FAIL; *ppstm = &stm->IStream_iface; return S_OK; }
unsigned char *ChmDoc::GetData(const char *fileName, size_t *lenOut) { ScopedMem<char> fileNameTmp; if (!str::StartsWith(fileName, "/")) { fileNameTmp.Set(str::Join("/", fileName)); fileName = fileNameTmp; } else if (str::StartsWith(fileName, "///")) { fileName += 2; } struct chmUnitInfo info; int res = chm_resolve_object(chmHandle, fileName, &info); if (CHM_RESOLVE_SUCCESS != res && str::FindChar(fileName, '\\')) { // Microsoft's HTML Help CHM viewer tolerates backslashes in URLs fileNameTmp.SetCopy(fileName); str::TransChars(fileNameTmp, "\\", "/"); fileName = fileNameTmp; res = chm_resolve_object(chmHandle, fileName, &info); } if (CHM_RESOLVE_SUCCESS != res) return nullptr; size_t len = (size_t)info.length; if (len > 128 * 1024 * 1024) { // don't allow anything above 128 MB return nullptr; } // +1 for 0 terminator for C string compatibility ScopedMem<unsigned char> data((unsigned char *)malloc(len + 1)); if (!data) return nullptr; if (!chm_retrieve_object(chmHandle, &info, data.Get(), 0, len)) return nullptr; data[len] = '\0'; if (lenOut) *lenOut = len; return data.StealData(); }
bool ChmDoc::HasData(const char* fileName) { if (!fileName) return nullptr; AutoFree tmpName; if (!str::StartsWith(fileName, "/")) { tmpName.Set(str::Join("/", fileName)); fileName = tmpName; } else if (str::StartsWith(fileName, "///")) fileName += 2; struct chmUnitInfo info; return chm_resolve_object(chmHandle, fileName, &info) == CHM_RESOLVE_SUCCESS; }
/* * Class: org_chm4j_ChmEntry * Method: readContent * Signature: (Ljava/lang/String;Ljava/lang/String;)[B */ JNIEXPORT jbyteArray JNICALL Java_org_chm4j_ChmEntry_readContent (JNIEnv *env, jobject jobj, jstring jfilename, jstring jpath) { // opens the file const char *filename = (*env)->GetStringUTFChars(env, jfilename, 0); struct chmFile* cFile = chm_open(filename); (*env)->ReleaseStringUTFChars(env, jfilename, filename); if(cFile == NULL) { J_ThrowException(env, "java/io/IOException", "failed to open the file"); return NULL; } // resolves entry struct chmUnitInfo cUnit; const char *path = (*env)->GetStringUTFChars(env, jpath, NULL); int res = chm_resolve_object(cFile, path, &cUnit); (*env)->ReleaseStringUTFChars(env, jpath, path); if(res != CHM_RESOLVE_SUCCESS) { // close the file chm_close(cFile); J_ThrowException(env, "java.io.IOException", "failed to resolve entry"); return NULL; } // retrieves entry content unsigned char* buf = (unsigned char*) malloc(sizeof(unsigned char) * cUnit.length); if(buf == NULL) { // close the file chm_close(cFile); J_ThrowException(env, "java.io.IOException", "failed to allocate buffer"); return NULL; } jlong nbRead = (jlong) chm_retrieve_object(cFile, &cUnit, buf, 0, cUnit.length); // close the file chm_close(cFile); // creates and fills java byte array jbyteArray data = (*env)->NewByteArray(env, nbRead); if(nbRead > 0) { (*env)->SetByteArrayRegion(env, data, 0, nbRead, buf); } free(buf); return data; }
static HRESULT WINAPI ITSProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) { ITSProtocol *This = impl_from_IInternetProtocol(iface); BINDINFO bindinfo; DWORD bindf = 0, len; LPWSTR file_name, mime, object_name, p; LPCWSTR ptr; struct chmFile *chm_file; struct chmUnitInfo chm_object; int res; HRESULT hres; static const WCHAR separator[] = {':',':',0}; TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); ptr = skip_schema(szUrl); if(!ptr) return INET_E_USE_DEFAULT_PROTOCOLHANDLER; memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(BINDINFO); hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo); if(FAILED(hres)) { WARN("GetBindInfo failed: %08x\n", hres); return hres; } ReleaseBindInfo(&bindinfo); len = strlenW(ptr)+3; file_name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); memcpy(file_name, ptr, len*sizeof(WCHAR)); hres = UrlUnescapeW(file_name, NULL, &len, URL_UNESCAPE_INPLACE); if(FAILED(hres)) { WARN("UrlUnescape failed: %08x\n", hres); HeapFree(GetProcessHeap(), 0, file_name); return hres; } p = strstrW(file_name, separator); if(!p) { WARN("invalid url\n"); HeapFree(GetProcessHeap(), 0, file_name); return report_result(pOIProtSink, STG_E_FILENOTFOUND); } *p = 0; chm_file = chm_openW(file_name); if(!chm_file) { WARN("Could not open chm file\n"); HeapFree(GetProcessHeap(), 0, file_name); return report_result(pOIProtSink, STG_E_FILENOTFOUND); } object_name = p+2; len = strlenW(object_name); if(*object_name != '/' && *object_name != '\\') { memmove(object_name+1, object_name, (len+1)*sizeof(WCHAR)); *object_name = '/'; len++; } if(object_name[len-1] == '/') object_name[--len] = 0; for(p=object_name; *p; p++) { if(*p == '\\') *p = '/'; } remove_dot_segments(object_name); TRACE("Resolving %s\n", debugstr_w(object_name)); memset(&chm_object, 0, sizeof(chm_object)); res = chm_resolve_object(chm_file, object_name, &chm_object); if(res != CHM_RESOLVE_SUCCESS) { WARN("Could not resolve chm object\n"); HeapFree(GetProcessHeap(), 0, file_name); chm_close(chm_file); return report_result(pOIProtSink, STG_E_FILENOTFOUND); } IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, strrchrW(object_name, '/')+1); /* FIXME: Native doesn't use FindMimeFromData */ hres = FindMimeFromData(NULL, object_name, NULL, 0, NULL, 0, &mime, 0); HeapFree(GetProcessHeap(), 0, file_name); if(SUCCEEDED(hres)) { IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime); CoTaskMemFree(mime); } release_chm(This); /* Native leaks handle here */ This->chm_file = chm_file; This->chm_object = chm_object; hres = IInternetProtocolSink_ReportData(pOIProtSink, BSCF_FIRSTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE, chm_object.length, chm_object.length); if(FAILED(hres)) { WARN("ReportData failed: %08x\n", hres); release_chm(This); return report_result(pOIProtSink, hres); } hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_BEGINDOWNLOADDATA, NULL); return report_result(pOIProtSink, hres); }
static void chmfile_system_info(struct chmFile *cfd, ChmFile *chmfile) { struct chmUnitInfo ui; unsigned char buffer[4096]; int index = 0; unsigned char* cursor = NULL; u_int16_t value = 0; u_int32_t lcid = 0; size_t size = 0; if (chm_resolve_object(cfd, "/#SYSTEM", &ui) != CHM_RESOLVE_SUCCESS) return; size = chm_retrieve_object(cfd, &ui, buffer, 4L, 4096); if (!size) return; buffer[size - 1] = 0; for(;;) { // This condition won't hold if I process anything // except NUL-terminated strings! if(index > size - 1 - (long)sizeof(u_int16_t)) break; cursor = buffer + index; value = UINT16ARRAY(cursor); g_debug("system value = %d", value); switch(value) { case 0: index += 2; cursor = buffer + index; chmfile->hhc = g_strdup_printf("/%s", buffer + index + 2); g_debug("hhc %s", chmfile->hhc); break; case 1: index += 2; cursor = buffer + index; chmfile->hhk = g_strdup_printf("/%s", buffer + index + 2); g_debug("hhk %s", chmfile->hhk); break; case 2: index += 2; cursor = buffer + index; chmfile->home = g_strdup_printf("/%s", buffer + index + 2); g_debug("home %s", chmfile->home); break; case 3: index += 2; cursor = buffer + index; chmfile->title = g_strdup((char *)buffer + index + 2); g_debug("title %s", chmfile->title); break; case 4: // LCID stuff index += 2; cursor = buffer + index; lcid = UINT32ARRAY(buffer + index + 2); g_debug("lcid %x", lcid); chmfile->encoding = get_encoding_by_lcid(lcid); break; case 6: index += 2; cursor = buffer + index; if(!chmfile->hhc) { char *hhc, *hhk; hhc = g_strdup_printf("/%s.hhc", buffer + index + 2); hhk = g_strdup_printf("/%s.hhk", buffer + index + 2); if (chm_resolve_object(cfd, hhc, &ui) == CHM_RESOLVE_SUCCESS) chmfile->hhc = hhc; if (chm_resolve_object(cfd, hhk, &ui) == CHM_RESOLVE_SUCCESS) chmfile->hhk = hhk; } break; case 16: index += 2; cursor = buffer + index; g_debug("font %s", buffer + index + 2); break; default: index += 2; cursor = buffer + index; } value = UINT16ARRAY(cursor); index += value + 2; } }
/* * callback function for enumerate API */ static int _print_ui(struct chmFile *h, struct chmUnitInfo *ui, void *context) { static char szBuf[128]; memset(szBuf, 0, 128); if(ui->flags & CHM_ENUMERATE_NORMAL) strcpy(szBuf, "normal "); else if(ui->flags & CHM_ENUMERATE_SPECIAL) strcpy(szBuf, "special "); else if(ui->flags & CHM_ENUMERATE_META) strcpy(szBuf, "meta "); if(ui->flags & CHM_ENUMERATE_DIRS) strcat(szBuf, "dir"); else if(ui->flags & CHM_ENUMERATE_FILES) strcat(szBuf, "file"); struct chmfile * f = (struct chmfile*)context; if(f && f->filename && strlen(f->filename)) { if(strcmp(f->filename,ui->path)==0) { //printf("resolving %s\n", (char*)f->filename); if (CHM_RESOLVE_SUCCESS == chm_resolve_object(h, f->filename, ui)) { f->data = malloc(ui->length+1); memset(f->data ,0,ui->length+1); /* printf(" object: <%d, %lu, %lu>\n", ui->space, (unsigned long)ui->start, (unsigned long)ui->length); */ chm_retrieve_object(h, ui, (unsigned char*)f->data, 0, ui->length); f->len = ui->length+1; return CHM_ENUMERATOR_SUCCESS; } } }else{ char out[1024]; memset(out,0,sizeof(1024)); sprintf(out," %1d %8d %8d %s\t\t%s\n", (int)ui->space, (int)ui->start, (int)ui->length, szBuf, ui->path); if(f->data==NULL){ f->data = malloc(strlen(out)+1); memset(f->data,0,strlen(out)+1); f->len = strlen(out)+1; }else{ f->data = realloc(f->data,f->len+strlen(out)); f->len += strlen(out); } //sprintf(f->data+strlen(f->data),"%s",out); strcat(f->data,out); } return CHM_ENUMERATOR_CONTINUE; }
bool chm_read(chm_t* chm, FILE* fd) { if (fseek(fd, 0, SEEK_SET) != 0) return false; unsigned char sbuffer[256]; unsigned int sremain; unsigned char *sbufpos; chm_unitinfo uiLzxc; chm_lzxc_ctldata ctlData; memset(&uiLzxc, 0, sizeof(uiLzxc)); memset(&ctlData, 0, sizeof(ctlData)); chm->fd = fd; chm->lzx_state = NULL; chm->cache_blocks = NULL; chm->cache_block_indices = NULL; chm->cache_num_blocks = 0; /* read and verify header */ sremain = CHM_ITSF_V3_LEN; sbufpos = sbuffer; if (_chm_fetch_bytes(chm, sbuffer, (uqword)0, sremain) != sremain || !_unmarshal_itsf_header(&sbufpos, &sremain, &chm->itsf)) { return false; } /* stash important values from header */ chm->dir_offset = chm->itsf.dir_offset; chm->dir_len = chm->itsf.dir_len; chm->data_offset = chm->itsf.data_offset; /* now, read and verify the directory header chunk */ sremain = CHM_ITSP_V1_LEN; sbufpos = sbuffer; if (_chm_fetch_bytes(chm, sbuffer, (uqword)chm->itsf.dir_offset, sremain) != sremain || !_unmarshal_itsp_header(&sbufpos, &sremain, &chm->itsp)) { return false; } /* grab essential information from ITSP header */ chm->dir_offset += chm->itsp.header_len; chm->dir_len -= chm->itsp.header_len; chm->index_root = chm->itsp.index_root; chm->index_head = chm->itsp.index_head; chm->block_len = chm->itsp.block_len; /* if the index root is -1, this means we don't have any PMGI blocks. * as a result, we must use the sole PMGL block as the index root */ if (chm->index_root <= -1) chm->index_root = chm->index_head; /* By default, compression is enabled. */ chm->compression_enabled = 1; /* prefetch most commonly needed unit infos */ if (CHM_RESOLVE_SUCCESS != chm_resolve_object(chm, _CHMU_RESET_TABLE, &chm->rt_unit) || chm->rt_unit.space == CHM_COMPRESSED || CHM_RESOLVE_SUCCESS != chm_resolve_object(chm, _CHMU_CONTENT, &chm->cn_unit) || chm->cn_unit.space == CHM_COMPRESSED || CHM_RESOLVE_SUCCESS != chm_resolve_object(chm, _CHMU_LZXC_CONTROLDATA, &uiLzxc) || uiLzxc.space == CHM_COMPRESSED) { chm->compression_enabled = 0; } /* read reset table info */ if (chm->compression_enabled) { sremain = CHM_LZXC_RESETTABLE_V1_LEN; sbufpos = sbuffer; if (chm_retrieve_object(chm, &chm->rt_unit, sbuffer, 0, sremain) != sremain || !_unmarshal_lzxc_reset_table(&sbufpos, &sremain, &chm->reset_table)) { chm->compression_enabled = 0; } } /* read control data */ if (chm->compression_enabled) { sremain = (unsigned int)uiLzxc.length; if (uiLzxc.length > sizeof(sbuffer)) { return false; } sbufpos = sbuffer; if (chm_retrieve_object(chm, &uiLzxc, sbuffer, 0, sremain) != sremain || !_unmarshal_lzxc_control_data(&sbufpos, &sremain, &ctlData)) { chm->compression_enabled = 0; } chm->window_size = ctlData.windowSize; chm->reset_interval = ctlData.resetInterval; chm->reset_blkcount = chm->reset_interval / (chm->window_size / 2) * ctlData.windowsPerReset; } /* initialize cache */ chm_set_param(chm, CHM_PARAM_MAX_BLOCKS_CACHED, CHM_MAX_BLOCKS_CACHED); return true; }