home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- #include "xp_mcom.h"
- #include "client.h"
- #include "hotlist.h"
-
- static int32 hot_measure_Separator(HotlistStruct * item, int bLongFormat, int nIndent);
-
-
- #define TEXT_INDENT 3
- #define SEPATATOR_COUNT 20
- /*
- * Measure a boring URL hotlist entry and return the length in bytes
- *
- * Short format:
- * " item->address\n"
- * where there are nIndent number of spaces before the item
- *
- * Long format:
- * int16 type
- * item->name\n
- * item->address\n
- * int32 addition_date
- * int32 last_visit_date
- * item->description\0
- *
- * The item->description field is *NOT* \n terminated since it might
- * be a multi-line string and is therefore \0 terminated
- */
- PRIVATE int32
- hot_measure_URL(HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- int32 iSpace = 0;
-
- if(!item)
- return(0);
-
- if(bLongFormat) {
-
- /* type, addition_date, last_visit_date + 2 \n's + 1 \0 */
- iSpace += 2 + 4 + 4 + 2 + 1;
-
- if(item->name)
- iSpace += XP_STRLEN(item->name);
- if(item->description)
- iSpace += XP_STRLEN(item->description);
-
- } else {
-
- /* space indentation and '\n' terminator */
- iSpace = 1 + nIndent;
-
- }
-
- /* the address appears in both formats */
- if(item->address)
- iSpace += XP_STRLEN(item->address);
-
- return(iSpace);
-
- }
-
- /*
- * Measure a header entry and all its children
- *
- * Short format:
- * " item->name\n"
- * " child1->address\n"
- * " child2->address\n"
- * where there are nIndent number of spaces before the item and
- * TEXT_INDENT spaces between levels
- *
- * Long format:
- * int16 type
- * item->name\n
- * int32 addition_date
- * int32 number of children
- * item->description\0
- *
- * The item->description field is *NOT* \n terminated since it might
- * be a multi-line string and is therefore \0 terminated. Note that
- * the address field is *NOT* written for headers since its it meaningless
- */
- PRIVATE int32
- hot_measure_Header(HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- XP_List * list;
- int32 iSpace = 0;
-
- if(!item)
- return(0);
-
- if(bLongFormat) {
-
- /* type, addition_date, last_visit_date + # children + 2 \n's + 1 \0 */
- iSpace += 2 + 4 + 4 + 2 + 1;
-
- if(item->description)
- iSpace += XP_STRLEN(item->description);
-
- } else {
-
- /* space indentation and '\n' terminator */
- iSpace = 1 + nIndent;
-
- }
-
- /* the name appears in both formats */
- if(item->name)
- iSpace += XP_STRLEN(item->name);
-
-
- /* if no children just return */
- if(!item->children)
- return(iSpace);
-
- /* measure the amount of space taken up by this item's children */
- for(list = item->children->next; list; list = list->next) {
- HotlistStruct * child = (HotlistStruct *) list->object;
-
- if(!child)
- continue;
-
- switch(child->type) {
- case HOT_URLType:
- iSpace += hot_measure_URL(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case HOT_HeaderType:
- iSpace += hot_measure_Header(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case HOT_SeparatorType:
- iSpace += hot_measure_Separator(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- default:
- break;
- }
-
- }
-
- return(iSpace);
-
- }
-
-
- /*
- * Measure a separator entry and return the length in bytes
- *
- * Short format:
- * " ---------------------\n"
- * where there are nIndent number of spaces before the item
- * and 20 dashes
- *
- * Long format:
- * int16 type
- */
- PRIVATE int32
- hot_measure_Separator(HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- int32 iSpace = 0;
-
- if(!item)
- return(0);
-
- if(bLongFormat) {
-
- /* type */
- iSpace = 2;
-
- } else {
-
- /* space indentation and '\n' terminator */
- iSpace = 1 + nIndent + 20;
-
- }
-
- return(iSpace);
-
- }
-
-
- /*
- * Write out a boring URL hotlist entry. See comment at the top of
- * hot_measure_URL for the format used. Assume we start writing at
- * the start of the buffer passed in. Return a pointer to where the
- * buffer ends when we get done.
- */
- PRIVATE char *
- hot_write_URL(char * buffer, HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- int iLen;
- int32 lVal;
- int32 sVal;
-
- if(!item || !buffer)
- return(buffer);
-
- if(bLongFormat) {
-
- /* copy the type */
- sVal = (int16) item->type;
- iLen = 2;
- XP_MEMCPY(buffer, &sVal, iLen);
- buffer += iLen;
-
- /* copy the name */
- if(item->name) {
- iLen = XP_STRLEN(item->name);
- XP_MEMCPY(buffer, item->name, iLen);
- buffer += iLen;
- }
-
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* copy the address */
- if(item->address) {
- iLen = XP_STRLEN(item->address);
- XP_MEMCPY(buffer, item->address, iLen);
- buffer += iLen;
- }
-
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* addition date */
- lVal = (int32) item->addition_date;
- iLen = 4;
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* last visit date */
- lVal = (int32) item->last_visit;
- iLen = 4;
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* copy the description */
- if(item->description) {
- iLen = XP_STRLEN(item->description);
- XP_MEMCPY(buffer, item->description, iLen);
- buffer += iLen;
- }
-
- /* put the \n terminator on */
- *buffer++ = '\0';
-
- } else {
-
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
-
- if(item->address) {
- XP_STRCPY(buffer, item->address);
- buffer += XP_STRLEN(item->address);
- }
-
- *buffer++ = '\n';
-
- }
-
- return(buffer);
-
- }
-
- /*
- * Write out a separator entry. See comment at the top of
- * hot_measure_Separator for the format used. Assume we start writing at
- * the start of the buffer passed in. Return a pointer to where the
- * buffer ends when we get done.
- */
- PRIVATE char *
- hot_write_Separator(char * buffer, HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- int iLen;
- #if 0
- int32 lVal;
- #endif
- int32 sVal;
-
- if(!item || !buffer)
- return(buffer);
-
- if(bLongFormat) {
-
- /* copy the type */
- sVal = (int16) item->type;
- iLen = 2;
- XP_MEMCPY(buffer, &sVal, iLen);
- buffer += iLen;
-
- } else {
-
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
-
- XP_MEMSET(buffer, '-', SEPATATOR_COUNT);
- buffer += SEPATATOR_COUNT;
-
- *buffer++ = '\n';
-
- }
-
- return(buffer);
-
- }
-
-
- /*
- * Write out a hotlist header entry. See comment at the top of
- * hot_measure_Header for the format used. Assume we start writing at
- * the start of the buffer passed in. Return a pointer to where the
- * buffer ends when we get done.
- */
- PRIVATE char *
- hot_write_Header(char * buffer, HotlistStruct * item, int bLongFormat, int nIndent)
- {
-
- XP_List * list;
- int iLen;
- int32 lVal;
- int32 sVal;
-
- if(!item || !buffer)
- return(buffer);
-
- if(bLongFormat) {
-
- /* copy the type */
- sVal = (int16) item->type;
- iLen = 2;
- XP_MEMCPY(buffer, &sVal, iLen);
- buffer += iLen;
-
- /* copy the name */
- if(item->name) {
- iLen = XP_STRLEN(item->name);
- XP_MEMCPY(buffer, item->name, iLen);
- buffer += iLen;
- }
-
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* addition date */
- lVal = (int32) item->addition_date;
- iLen = 4;
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* number of children */
- lVal = XP_ListCount(item->children);
- iLen = 4;
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* copy the description */
- if(item->description) {
- iLen = XP_STRLEN(item->description);
- XP_MEMCPY(buffer, item->description, iLen);
- buffer += iLen;
- }
-
- /* put the \n terminator on */
- *buffer++ = '\0';
-
- } else {
-
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
-
- if(item->name) {
- XP_STRCPY(buffer, item->name);
- buffer += XP_STRLEN(item->name);
- }
-
- *buffer++ = '\n';
-
- }
-
- /* if no children just get out now */
- if(!item->children)
- return(buffer);
-
- /* write out the children */
- for(list = item->children->next; list; list = list->next) {
- HotlistStruct * child = (HotlistStruct *) list->object;
-
- if(!child)
- continue;
-
- switch(child->type) {
- case HOT_URLType:
- buffer = hot_write_URL(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case HOT_HeaderType:
- buffer = hot_write_Header(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case HOT_SeparatorType:
- buffer = hot_write_Separator(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- default:
- break;
- }
-
- }
-
- return(buffer);
-
- }
-
-
- /*
- * Take a URL packed in a block the way hot_write_URL packs it.
- * Return the new item if we created one
- */
- PRIVATE HotlistStruct *
- hot_read_URL(char * buffer, HotlistStruct * pListParent, HotlistStruct * item, int bLongFormat, int32 * lBytesEaten)
- {
-
- HotlistStruct * new_item = NULL;
-
- if(!buffer)
- return(NULL);
-
- if(bLongFormat) {
-
- int32 addition, visit;
-
- /* get the name */
- char * name = buffer;
- char * address = strchr(name, '\n');
- char * description = NULL;
- char * ptr;
- if(!address)
- return(NULL);
-
- *address++ = '\0';
-
- /* get the address */
- ptr = strchr(address, '\n');
- if(!ptr)
- return(NULL);
-
- *ptr++ = '\0';
-
- /* addition date */
- XP_MEMCPY(&addition, ptr, 4);
- ptr += 4;
-
- /* visiting date */
- XP_MEMCPY(&visit, ptr, 4);
- ptr += 4;
-
- /* get the description (it should be NULL terminated) */
- description = ptr;
-
- /* we should really strip leading whitespace */
- new_item = HOT_CreateEntry(HOT_URLType, name, address, 0, visit);
- new_item->addition_date = addition;
- new_item->description = XP_STRDUP(description);
- *lBytesEaten = XP_STRLEN(description) + (description - buffer) + 1;
-
- } else {
-
- char * end = strchr(buffer, '\n');
-
- /* if there was a return NULL terminate the current string */
- if(end)
- *end++ = '\0';
-
- /* we should really strip leading whitespace */
- new_item = HOT_CreateEntry(HOT_URLType, buffer, buffer, 0, 0);
- new_item->addition_date = time ((time_t *) NULL);
- *lBytesEaten = XP_STRLEN(buffer) + 1;
-
- }
-
- if(item)
- HOT_InsertItemAfter(item, new_item);
- else
- HOT_InsertItemInHeaderOrAfterItem(pListParent, new_item);
-
- return(new_item);
-
- }
-
-
- /*
- * Take a separator and insert it
- */
- PRIVATE HotlistStruct *
- hot_read_Separator(char * buffer, HotlistStruct * pListParent, HotlistStruct * item, int bLongFormat, int32 * lBytesEaten)
- {
- #if 0
- int32 kids = 0;
- int16 sVal;
- #endif
- HotlistStruct * new_item = NULL;
-
- if(!buffer)
- return(NULL);
-
- /* can only read long format headers */
- if(bLongFormat) {
-
- new_item = HOT_CreateEntry(HOT_SeparatorType, NULL, NULL, 0, 0);
- *lBytesEaten = 0;
-
- if(item)
- HOT_InsertItemAfter(item, new_item);
- else
- HOT_InsertItemInHeaderOrAfterItem(pListParent, new_item);
-
- return(new_item);
-
- }
-
- return(NULL);
-
- }
-
-
-
- /*
- * Take a header and children packed in a block the way hot_write_Header
- * packs it. Return the new header item if we created one
- */
- PRIVATE HotlistStruct *
- hot_read_Header(char * buffer, HotlistStruct * pListParent, HotlistStruct * item, int bLongFormat, int32 * lBytesEaten)
- {
-
- int32 kids = 0;
- int16 sVal;
- HotlistStruct * new_item = NULL;
-
- if(!buffer)
- return(NULL);
-
- /* can only read long format headers */
- if(bLongFormat) {
-
- int32 addition;
-
- /* get the name */
- char * name = buffer;
- char * ptr = strchr(name, '\n');
- char * description = NULL;
- if(!ptr)
- return(NULL);
-
- /* skip over the \n but change it to a \0 so strcpy() will work */
- *ptr++ = '\0';
-
- /* addition date */
- XP_MEMCPY(&addition, ptr, 4);
- ptr += 4;
-
- /* number of children to read */
- XP_MEMCPY(&kids, ptr, 4);
- ptr += 4;
-
- /* get the description (it should be NULL terminated) */
- description = ptr;
-
- /* we should really strip leading whitespace */
- new_item = HOT_CreateEntry(HOT_HeaderType, name, NULL, 0, 0);
- new_item->addition_date = addition;
- new_item->description = XP_STRDUP(description);
- *lBytesEaten = XP_STRLEN(description) + (description - buffer) + 1;
-
- /* handle all of the kids now */
- if(kids) {
-
- int i;
- HotlistStruct * kid = NULL;
-
- new_item->children = XP_ListNew();
- buffer += *lBytesEaten;
-
- for(i = 0; i < kids; i++) {
-
- int32 lEat;
-
- /* determine the type of the next entry */
- sVal = 0;
- XP_MEMCPY(&sVal, buffer, 2);
- buffer += 2;
- *lBytesEaten += 2;
-
- switch(sVal) {
- case HOT_URLType:
- kid = hot_read_URL(buffer, new_item, kid, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- break;
- case HOT_HeaderType:
- kid = hot_read_Header(buffer, new_item, kid, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- break;
- case HOT_SeparatorType:
- kid = hot_read_Separator(buffer, new_item, kid, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- break;
- default:
- /* bogus type. Who knows whats going on. Just quit and get out */
- break;
- }
-
- }
-
- } else {
-
- /* no kids */
- new_item->children = NULL;
-
- }
-
- }
-
- if(item)
- HOT_InsertItemAfter(item, new_item);
- else
- HOT_InsertItemInHeaderOrAfterItem(pListParent, new_item);
-
- return(new_item);
-
- }
-
-
-
- /*
- * Allocate and return a string that contains the text representation of
- * a list of hotlist entries (including headers and their contents).
- * The caller is responsible for freeing the string
- */
- PUBLIC char *
- HOT_ConvertSelectionsToBlock(HotlistStruct ** list, int iCount, int bLongFormat, int32 * lTotalLen)
- {
-
- int i, j;
- int bSkip;
- int16 marker;
- int32 iSpace = 0;
- HotlistStruct * item;
- HotlistStruct * pParent;
- char * pString;
- char * pOriginal;
-
- for(i = 0; i < iCount; i++) {
-
- /* don't skip yet */
- bSkip = FALSE;
-
- /* make sure we have a valid item */
- item = list[i];
- if(!item)
- continue;
-
- /*
- * if our parent is in the list don't add ourselves, we will have
- * been added when our parent got added. Ugh. This is going to be
- * n^2 over the number of selected items
- */
- for(pParent = item->parent; pParent && !bSkip; pParent = pParent->parent) {
- for(j = 0; (j < iCount) && (!bSkip) ; j++)
- if(list[j] == pParent)
- bSkip = TRUE;
- }
-
- if(bSkip)
- continue;
-
- /* decide how much space we need */
- switch(item->type) {
- case HOT_URLType:
- iSpace += hot_measure_URL(item, bLongFormat, 0);
- break;
- case HOT_HeaderType:
- iSpace += hot_measure_Header(item, bLongFormat, 0);
- break;
- case HOT_SeparatorType:
- iSpace += hot_measure_Separator(item, bLongFormat, 0);
- break;
- default:
- break;
- }
-
- }
-
- /* leave room for end of list marker */
- if(bLongFormat)
- iSpace += 2;
-
- /* leave room for the termination character */
- iSpace++;
-
- #ifdef XP_WIN16
- if(iSpace > 32000)
- return(NULL);
- #endif
-
- /* allocate the string */
- pOriginal = pString = (char *) XP_ALLOC(iSpace * sizeof(char));
- if(!pString)
- return(NULL);
-
- /* Make a big string */
- for(i = 0; i < iCount; i++) {
-
- bSkip = FALSE;
-
- /* make sure we have a valid item */
- item = list[i];
- if(!item)
- continue;
-
- /*
- * if our parent is in the list don't add ourselves, we will have
- * been added when our parent got added. Ugh. This is going to be
- * n^2 over the number of selected items
- */
- for(pParent = item->parent; pParent && !bSkip; pParent = pParent->parent) {
- for(j = 0; (j < iCount) && (!bSkip) ; j++)
- if(list[j] == pParent)
- bSkip = TRUE;
- }
-
- if(bSkip)
- continue;
-
- /* write out the item */
- switch(item->type) {
- case HOT_URLType:
- pString = hot_write_URL(pString, item, bLongFormat, 0);
- break;
- case HOT_HeaderType:
- pString = hot_write_Header(pString, item, bLongFormat, 0);
- break;
- case HOT_SeparatorType:
- pString = hot_write_Separator(pString, item, bLongFormat, 0);
- break;
- default:
- break;
- }
-
- }
-
- /* stick the end of list marker on so that when we are decoding this */
- /* block we know when we are done */
- if(bLongFormat) {
- marker = 12345;
- XP_MEMCPY(pString, &marker, 2);
- pString +=2;
- }
-
- /* end the string and return the total length to our caller */
- *pString++ = '\0';
- *lTotalLen = (pString - pOriginal);
- return(pOriginal);
-
- }
-
-
-
- /*
- * Take a block of memory formatted by HOT_ConvertSelectionsToBlock and insert
- * the items it represents into the hotlist following 'item'. If item is
- * NULL insert at the beginning of the hotlist.
- */
- PUBLIC void
- HOT_InsertBlockAt(char * pOriginalBlock, HotlistStruct * item, int bLongFormat, int32 lTotalLen)
- {
-
- int16 sVal; /* 16-bit scratch variable */
- int32 lBytesEaten = 0; /* total number of bytes eaten */
- int32 lEat; /* number of bytes eaten on this item */
- char * pCurrentPos;
- char * pBlock;
- HotlistStruct * pParent = HOT_GetHotlist();
-
- if(!pOriginalBlock)
- return;
-
- /* make a copy of the string we can write into */
- pCurrentPos = pBlock = (char *) XP_ALLOC(lTotalLen + 1);
- if(!pBlock)
- return;
-
- /* copy the data over and make sure we are NULL terminated to make life easier */
- XP_MEMCPY(pBlock, pOriginalBlock, lTotalLen);
- pBlock[lTotalLen] = '\0';
-
- /*
- * if our very first element is a header then we really want to insert
- * everything into the header and not after it --- I think.
- */
- if(item && item->type == HOT_HeaderType) {
- pParent = item;
- item = NULL;
-
- /*
- * gack! if we are inserting under a header make sure its set up
- * to accept children
- */
- if(!pParent->children)
- pParent->children = XP_ListNew();
- }
-
- /* long format can have all kinds of different types of things in it */
- if(bLongFormat) {
-
- while(lBytesEaten < lTotalLen) {
-
- /* determine the type of the next entry */
- sVal = 0;
- XP_MEMCPY(&sVal, pCurrentPos, 2);
- pCurrentPos += 2;
- lBytesEaten += 2;
-
- switch(sVal) {
- case HOT_URLType:
- item = hot_read_URL(pCurrentPos, pParent, item, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
- case HOT_HeaderType:
- item = hot_read_Header(pCurrentPos, pParent, item, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
- case HOT_SeparatorType:
- item = hot_read_Separator(pCurrentPos, pParent, item, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
- default:
- /* bogus type. Who knows whats going on. Just quit and get out */
- return;
- break;
- }
-
- }
-
- } else {
-
- /* short format is just a list of URLs separated by \n's */
- while(lBytesEaten < lTotalLen) {
-
- item = hot_read_URL(pCurrentPos, pParent, item, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
-
- /* if we just walked over a \0 we are done */
- if(pOriginalBlock[lBytesEaten - 1] == '\0')
- lBytesEaten = lTotalLen;
-
- }
-
- }
-
- /* mark the bookmark list as changed and clean up */
- HOT_SetModified();
- XP_FREE(pBlock);
-
- }
-