_INDEXING IMAGE DATABASES_ by Art Sulger [LISTING ONE] // Mapper.hpp #define NOLOCK 1 // these constants would be in a default file // or WIN.INI (for a Windows app): char cMap[] = "C:\\MAPTEST" ; // Mapper.Dat location char cLinkL[] = "C:\\MAPTEST" ; // Linkedl.Dat location #ifndef MAPPER #define MAPPER #include #include #include #include #include #include class Mapper { private : int fp ; // file pointer long lBytePosition ; char cBytePosition [9] ; // hex representation of long value char * cMapperFileSpec ; // Mapper.dat full file name struct MapperBuffer // layout of the Index entry { char cDevice [1] ; // device where image is char cPath [2] ; // directory or Jukebox platter char cFileExtension [3] ; // type of image } Map ; void WipeMapper(){strnset((char *)&Map,'\0',sizeof(Map));} char cMwholefilename[19]; public : Mapper() ; ~Mapper() ; int Close() ; char * Hexbytes(){return cBytePosition ;} long lMapSlot() { return lBytePosition ; } char * LockSpot() ; int Open() ; char * Read(long lOffset) ; int Write() ; // commit to disk int Write(char * Extension, // Image type char * Path, // subdirectory or jukebox platter char * Device) ; } ; #endif // MAPPER #ifndef LINKEDLIST #define LINKEDLIST class LinkedList { private : int fp ; // file pointer long lBytePosition ; char * cLinkedListFileSpec ; struct LinkedListBuffer { long Previous ; long Next ; long MapperAddress ; // points at Mapper Index entry } ll ; Mapper * M; public : LinkedList() ; ~LinkedList() ; int Close() ; int Linkin(long OldEntry) ; long lLinkSlot() { return lBytePosition ; } char * LastImage(long lOffset) ; char * LockSpot() ; long MapAddress() {return ll.MapperAddress ;} long Next(){return ll.Next ;} int Open() ; char * Read(long) ; int Write(char * Extension, // Image type char * Path, // subdir or jukebox platter char * Device) ; } ; #endif // LINKEDLIST [LISTING TWO] #include "Mapper.hpp" // M A P P E R M E T H O D S //-----------------constructor----------------------------- Mapper::Mapper() { fp = lBytePosition = 0 ; Open() ; } //------------------------oblivion------------------------- Mapper::~Mapper() { if (fp) { delete cMapperFileSpec ; close(fp) ; } fp = 0 ; } //-------------------open and close members----------------- Mapper::Open() { if (!fp) { // get file location defaults: cMapperFileSpec = new char [strlen(cMap) + 13] ; sprintf(cMapperFileSpec, "%s\\MAPPER.DAT", cMap) ; // append if exists, otherwise create : if (access(cMapperFileSpec, F_OK == -1)) { FILE * fd = fopen(cMapperFileSpec, "w+") ; fclose(fd) ; } if ((fp = sopen (cMapperFileSpec, O_RDWR, SH_DENYNO)) == -1) return -1 ; } return 0 ; } //------------------Close----------------------------------- Mapper::Close() { if (fp) { close(fp) ; fp = 0 ; } return 0 ; } //-------------------LockSpot------------------------------- char * Mapper::LockSpot() { if (!fp) Open() ; lBytePosition = lseek(fp, 0L, SEEK_END) ; WipeMapper() ; if (write(fp, &Map, sizeof(Map) ) == -1) return NULL ; lseek(fp, lBytePosition, SEEK_SET) ; #ifndef NOLOCK // don't let anyone else append if (locking(fp, LK_LOCK, (long)sizeof(Map)) == -1) return NULL ; #endif sprintf(cBytePosition,"%8.8lx", lBytePosition) ; return cBytePosition ; } //---------------------------Read--------------------------- char * Mapper::Read(long lOffset) { if (!fp) Open() ; if (lseek(fp, lOffset, SEEK_SET) == -1) return NULL ; if (read(fp, &Map, 6 ) == -1) // device,dir, & extension return NULL ; sprintf(cBytePosition, "%8.8lx", lOffset); // filename sprintf(cMwholefilename, "%1.1s:\\%1.2s\\%8.8s.%3.3s", Map.cDevice, // Image device Map.cPath, // Image path (or Jukebox disk) cBytePosition, // filename/offset in hex Map.cFileExtension ) ; // type (TIF,WP4,WP5...) return cMwholefilename; } //--------------------------Write-------------------------- Mapper::Write(char * Extension,// Image type char * Path, // Image subdir or juke platter char * Device)// Image device (single letter) { if (!fp) Open() ; memcpy((char *)&Map.cDevice, Device, 1) ; memcpy((char *)&Map.cPath, Path, sizeof(Map.cPath)) ; memcpy((char *)&Map.cFileExtension, Extension, sizeof(Map.cFileExtension)) ; return Write() ; } //---------------------------------------------------------- Mapper::Write() { lseek(fp, lBytePosition, SEEK_SET) ; if (write(fp, &Map, sizeof(Map) ) == -1) return -1 ; // should return error code here #ifndef NOLOCK if (locking(fp, LK_UNLCK, (long)sizeof(Map)) == -1) return - 1 ; // should return error code here #endif return 0 ; } // L I N K E D L I S T M E T H O D S //-------------------------constructor---------------------- LinkedList::LinkedList() { fp = 0 ; Open() ; M = new Mapper(); } //------------------------oblivion-------------------------- LinkedList::~LinkedList() { if (fp) close(fp) ; delete M ; } //-------------------open and close members----------------- LinkedList::Open() { int ok ; if (!fp) { cLinkedListFileSpec = new char [strlen(cLinkL) + 13] ; sprintf(cLinkedListFileSpec,"%s\\LINKEDL.DAT", cLinkL) ; // append if exists, otherwise create : if (access(cLinkedListFileSpec, F_OK == -1)) { FILE * fd = fopen(cLinkedListFileSpec, "w+") ; fclose(fd) ; if ((fp = sopen (cLinkedListFileSpec, O_RDWR, SH_DENYNO)) == -1) return -1 ; lBytePosition = lseek(fp, 0L, SEEK_END) ; // Write a -1 header because a '0' file name * -1 = 0 ll.Previous = ll.Next = 0 ; ll.MapperAddress = -1 ; lBytePosition = 0 ; lseek(fp, lBytePosition, SEEK_SET) ; if (write(fp, &ll, sizeof(ll) ) == -1) return -1 ; return 0 ; } else // file already exists if ((fp = sopen (cLinkedListFileSpec, O_RDWR, SH_DENYNO)) == -1) return -1 ; } return 0 ; } LinkedList::Close() { if (fp) { delete cLinkedListFileSpec ; close(fp) ; fp = 0 ; } return 0 ; } //---------------------LastImage---------------------------- char * LinkedList::LastImage(long lOffset) { Read(lOffset) ; while (ll.Next) Read(ll.Next); return (M->Read(ll.MapperAddress)) ; } //--------------------------Read--------------------------- char * LinkedList::Read(long lOffset) { char lbuf[9]; char buffer[7]; if (lOffset < 0) lOffset *= -1 ; lBytePosition = lOffset ; if (!fp) Open() ; if (lseek(fp, lOffset, SEEK_SET) == -1) return NULL ; if (read(fp, &ll, sizeof(ll) ) == -1) return NULL ; return (M->Read(ll.MapperAddress)); } //---------------------LockSpot----------------------------- char * LinkedList::LockSpot() { if (!fp) Open() ; lBytePosition = lseek(fp, 0L, SEEK_END) ; ll.Next = ll.Previous = 0 ; if (write(fp, &ll, sizeof(ll) ) == -1) return NULL ; lseek(fp, lBytePosition, SEEK_SET) ; #ifndef NOLOCK if (locking(fp, LK_LOCK, (long)sizeof(ll)) == -1) return NULL ; #endif M->LockSpot() ; ll.MapperAddress = M->lMapSlot() ; return M->Hexbytes() ; } //---------------------------Write-------------------------- LinkedList::Write(char * Extension, // Image type char * Path, // subdir or platter char * Device) { if (!fp) Open() ; lseek(fp, lBytePosition, SEEK_SET) ; if (write(fp, &ll, sizeof(ll) ) == -1) return -1 ; #ifndef NOLOCK if (locking(fp, LK_UNLCK, sizeof(ll)) == -1) return -1 ; #endif M->Write(Extension, Path, Device) ; return 0 ; } //---------------------------Write-------------------------- LinkedList::Linkin(long LLPr) { if (!fp) Open() ; lseek(fp, LLPr, SEEK_SET) ; if (read(fp, (char *)&ll, sizeof(ll) ) == -1) return -1 ; lseek(fp, LLPr, SEEK_SET) ; ll.Next = lBytePosition ; if (write(fp, (char *)&ll, sizeof(ll) ) == -1) return -1 ; lseek(fp, lBytePosition, SEEK_SET) ; if (read(fp, (char *)&ll, sizeof(ll) ) == -1) return -1 ; lseek(fp, lBytePosition, SEEK_SET) ; ll.Previous = LLPr ; if (write(fp, &ll, sizeof(ll) ) == -1) return -1 ; #ifndef NOLOCK if (locking(fp, LK_UNLCK, sizeof(ll)) == -1) return -1 ; #endif return 0 ; } [LISTING THREE] /* this program creates a Mapper.dat and LinkedL.dat and writes 1,000 single image entries and 1,000 entries of 4 page documents, then reads them back. The entries are stored in a sequential file as 4 byte character strings. */ char cKey[] = "C:\\MAPTEST\\KEYS.X" ; char cDev[] = "X"; // where 'images' are stored const long TestCount = 1000 ; const int MultiPage = 4 ; // # Images in multipage docs. union value // converts 4 byte chars to long and visa-versa { long lValue ; char cValue[sizeof(long)] ; } uValue ; Mapper * Map ; LinkedList * LL ; char * AvailableMapper ; #include "stdlib.h" int main(int argc, char * argv[]) { char cmd [32] ; FILE * fd ; int fp ; long i ; long lLong ; char szDir[3] ; sprintf(cmd, "DEL %s\\MAPPER.DAT", cMap) ; system(cmd) ; sprintf(cmd, "DEL %s\\LINKEDL.DAT", cLinkL) ; system(cmd) ; fd = fopen(cKey, "w") ; fclose(fd) ; fp = open(cKey, O_WRONLY) ; Map = new Mapper ; itoa(1, szDir, 10) ; // make up directory names for (i = 0; i < TestCount; i++) { Map->LockSpot() ; Map->Write("TIF", szDir, cDev) ; uValue.lValue = Map->lMapSlot() ; lseek(fp, 0, SEEK_END) ; write(fp, (char *)&uValue.cValue, sizeof(long)) ; if ((i / 100) * 100 == i) { itoa(i, szDir, 10) ; // change directory name printf("\t%ld", i) ; } } delete Map ; close(fp) ; // Build some Multi-page: fp = open(cKey, O_RDWR) ; printf("\nMulti-page Documents\n") ; LL = new LinkedList ; itoa(1, szDir, 10) ; // make up directory names for (i = 0; i < TestCount; i++) { LL->LockSpot() ; LL->Write("TIF", szDir, cDev) ; uValue.lValue = LL->lLinkSlot() ; uValue.lValue *= -1 ; // say we are a linked list entry lseek(fp, 0, SEEK_END) ; write(fp, (char *)&uValue.cValue, sizeof(long)) ; lLong = LL->lLinkSlot() ; for (int j = 1; j < MultiPage; j++) { // next pages: LL->LockSpot() ; LL->Write("TIF", szDir, cDev) ; LL->Linkin(lLong) ; lLong = LL->lLinkSlot() ; } if ((i / 100) * 100 == i) { itoa(i, szDir, 10) ; // change directory name printf("\t%ld", i) ; } } close(fp) ; delete LL ; // we can read them all back now: Map = new Mapper ; LL = new LinkedList ; fp = open(cKey, O_RDONLY) ; // open the keys lseek(fp, 0, SEEK_SET) ; printf("\n'Long'\tFilename\n") ; while (read(fp, (char *)&uValue.cValue, sizeof(long))) { if (uValue.lValue >= 0) printf("\n%ld\t%s", uValue.lValue, Map->Read(uValue.lValue)) ; else { printf("\n%ld\t%s", uValue.lValue, LL->Read(uValue.lValue)) ; while (LL->Next()) printf("\n%ld\t%s", uValue.lValue, LL->Read(LL->Next())) ; } } close(fp) ; delete Map ; delete LL ; return 0 ; } Example 1: struct Mapper { char Device ; char Path [2] ; char FileExtension [3] ; } Example 2: struct LinkedList { unsigned long Prev ; unsigned long MapperOffset ; unsigned long Next ; } ;