///////////////////////////////////////////////////////////////////////////// // Name: readshg.cpp // Purpose: Petr Smilauer's .SHG (Segmented Hypergraphics file) reading // code. // Note: .SHG is undocumented (anywhere!) so this is // reverse-engineering // and guesswork at its best. // Author: Petr Smilauer // Modified by: Wlodzimiez ABX Skiba 2003/2004 Unicode support // Ron Lee // Created: 01/01/99 // RCS-ID: $Id: readshg.cpp 35650 2005-09-23 12:56:45Z MR $ // Copyright: (c) Petr Smilauer // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #endif #include #include #include "readshg.h" #include "tex2any.h" // Returns the number of hotspots, and the array of hotspots. // E.g. // HotSpots *array; // int n = ParseSHG("thing.shg", &array); int ParseSHG( const wxChar* fileName, HotSpot **hotspots) { FILE* fSHG = wxFopen( fileName, _T("rb")); long offset; int nHotspots = 0; if(fSHG == 0) return 0; nHotspots = 0; //first, look at offset OFF_OFFSET to get another offset :-) fseek( fSHG, OFF_OFFSET, SEEK_SET); offset = 0L; // init whole 4-byte variable fread( &offset, 2, 1, fSHG); // get the offset in first two bytes.. if(offset == 0) // if zero, used next DWORD field fread( &offset, 4, 1, fSHG);// this is our offset for very long DIB offset += 9; // don't know hot this delta comes-about if(fseek( fSHG, offset, SEEK_SET) != 0) { fclose( fSHG); return -1; // this is probably because incorrect offset calculation. } fread( &nHotspots, 2, 1, fSHG); *hotspots = new HotSpot[nHotspots]; int nMacroStrings = 0; fread( &nMacroStrings, 2, 1, fSHG); // we can ignore the macros, as this is // repeated later, but we need to know how much to skip fseek( fSHG, 2, SEEK_CUR); // skip another 2 bytes I do not understand ;-) ShgInfoBlock sib; int i; int sizeOf = sizeof( ShgInfoBlock); for( i = 0 ; i < nHotspots ; ++i) { fread( &sib, sizeOf, 1, fSHG); // read one hotspot' info // analyse it: (*hotspots)[i].type = (HotspotType)(sib.hotspotType & 0xFB); (*hotspots)[i].left = sib.left; (*hotspots)[i].top = sib.top; (*hotspots)[i].right = sib.left + sib.width; (*hotspots)[i].bottom = sib.top + sib.height; (*hotspots)[i].IsVisible = ((sib.hotspotType & 4) == 0); (*hotspots)[i].szHlpTopic_Macro[0] = '\0'; } // we have it...now read-off the macro-string block if(nMacroStrings > 0) fseek( fSHG, nMacroStrings, SEEK_CUR); //nMacroStrings is byte offset... // and, at the last, read through the strings: hotspot-id[ignored], then topic/macro int c; for( i = 0 ; i < nHotspots ; ++i) { while( (c = fgetc( fSHG)) != 0) ; // now read it: int j = 0; while( (c = fgetc( fSHG)) != 0) { (*hotspots)[i].szHlpTopic_Macro[j] = (wxChar)c; ++j; } (*hotspots)[i].szHlpTopic_Macro[j] = 0; } fclose( fSHG); return nHotspots; } // Convert Windows .SHG file to HTML map file bool SHGToMap(wxChar *filename, wxChar *defaultFile) { // Test the SHG parser HotSpot *hotspots = NULL; int n = ParseSHG(filename, &hotspots); if (n == 0) return false; wxChar buf[100]; wxSnprintf(buf, sizeof(buf), _T("Converting .SHG file to HTML map file: there are %d hotspots in %s."), n, filename); OnInform(buf); wxChar outBuf[256]; wxStrcpy(outBuf, filename); StripExtension(outBuf); wxStrcat(outBuf, _T(".map")); FILE *fd = wxFopen(outBuf, _T("w")); if (!fd) { OnError(_T("Could not open .map file for writing.")); delete[] hotspots; return false; } wxFprintf(fd, _T("default %s\n"), defaultFile); for (int i = 0; i < n; i++) { wxChar *refFilename = _T("??"); TexRef *texRef = FindReference(hotspots[i].szHlpTopic_Macro); if (texRef) refFilename = texRef->refFile; else { wxChar buf[300]; wxSnprintf(buf, sizeof(buf), _T("Warning: could not find hotspot reference %s"), hotspots[i].szHlpTopic_Macro); OnInform(buf); } wxFprintf(fd, _T("rect %s %d %d %d %d\n"), refFilename, (int)hotspots[i].left, (int)hotspots[i].top, (int)hotspots[i].right, (int)hotspots[i].bottom); } wxFprintf(fd, _T("\n")); fclose(fd); delete[] hotspots; return true; }