mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-14 14:02:47 +00:00
889 lines
22 KiB
C
889 lines
22 KiB
C
/* -*- 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);
|
|
|
|
}
|