blob: e79929fb5ef85a16648634fee8238943cf1cc85e [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "DFPlatform.h"
#include "DFBuffer.h"
#include "DFCommon.h"
#include "DFString.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// DFBuffer //
// //
////////////////////////////////////////////////////////////////////////////////////////////////////
DFBuffer *DFBufferNew(void)
{
DFBuffer *buf = (DFBuffer *)xcalloc(1,sizeof(DFBuffer));
buf->retainCount = 1;
buf->alloc = 1;
buf->len = 0;
buf->data = (char *)xmalloc(buf->alloc*sizeof(char));
buf->data[0] = '\0';
return buf;
}
DFBuffer *DFBufferRetain(DFBuffer *buf)
{
if (buf == NULL)
return NULL;
buf->retainCount++;
return buf;
}
void DFBufferRelease(DFBuffer *buf)
{
if (buf == NULL)
return;
assert(buf->retainCount > 0);
buf->retainCount--;
if (buf->retainCount == 0) {
free(buf->data);
free(buf);
}
}
void DFStringBufferEnsureSpace(DFBuffer *buf, size_t len)
{
size_t want = buf->len + len + 1;
if (buf->alloc < want) {
while (buf->alloc < want)
buf->alloc *= 2;
buf->data = (char *)xrealloc(buf->data,buf->alloc);
}
}
void DFBufferAppendData(DFBuffer *buf, const char *data, size_t len)
{
if (buf == NULL)
return;
DFStringBufferEnsureSpace(buf,len);
memcpy(&buf->data[buf->len],data,len);
buf->data[buf->len + len] = '\0';
buf->len += len;
}
void DFBufferAppendString(DFBuffer *buf, const char *data)
{
DFBufferAppendData(buf,data,strlen(data));
}
void DFBufferAppendChar(DFBuffer *buf, char ch)
{
DFBufferAppendData(buf,&ch,1);
}
void DFBufferVFormat(DFBuffer *buf, const char *format, va_list ap)
{
if (buf == NULL) {
return;
}
va_list ap2;
va_copy(ap2,ap);
size_t nchars = vsnprintf(NULL,0,format,ap2);
va_end(ap2);
DFStringBufferEnsureSpace(buf,nchars);
va_copy(ap2,ap);
vsnprintf(&buf->data[buf->len],nchars+1,format,ap2);
va_end(ap2);
buf->len += nchars;
}
void DFBufferFormat(DFBuffer *buf, const char *format, ...)
{
va_list ap;
va_start(ap,format);
DFBufferVFormat(buf,format,ap);
va_end(ap);
}
DFBuffer *DFBufferReadFromFile(const char *filename, DFError **error)
{
FILE *file = fopen(filename,"rb");
if (file == NULL) {
DFErrorSetPosix(error,errno);
return NULL;
}
DFBuffer *buf = DFBufferNew();
size_t r;
char temp[1024];
while (0 < (r = fread(temp,1,1024,file)))
DFBufferAppendData(buf,temp,r);
fclose(file);
return buf;
}
DFBuffer *DFBufferReadFromStorage(DFStorage *storage, const char *filename, DFError **error)
{
void *data = 0;
size_t len = 0;
if (!DFStorageRead(storage,filename,&data,&len,error))
return NULL;;
DFBuffer *r = DFBufferNew();;
DFBufferAppendData(r,data,len);
free(data);
return r;
}
int DFBufferWriteToStorage(DFBuffer *buf, DFStorage *storage, const char *filename, DFError **error)
{
return DFStorageWrite(storage,filename,buf->data,buf->len,error);
}
int DFBufferWriteToFile(DFBuffer *buf, const char *filename, DFError **error)
{
return DFWriteDataToFile(buf->data,buf->len,filename,error);
}
int DFWriteDataToFile(const void *data, size_t len, const char *filename, DFError **error)
{
FILE *file = fopen(filename,"wb");
if (file == NULL) {
DFErrorSetPosix(error,errno);
return 0;
}
size_t w = fwrite(data,1,len,file);
if (w != len) {
DFErrorFormat(error,"Incomplete write");
fclose(file);
return 0;
}
fclose(file);
return 1;
}
// This file isn't really a great place for binaryToString and stringToBinary, but they needed
// to go somewhere after being moved into the DocFormats library from dfutil. At the time of
// writing, they're only used for by the test functions - perhaps we can have a TestLib.c file
// or similar?
char *binaryToString(DFBuffer *input)
{
const char *hexchars = "0123456789ABCDEF";
DFBuffer *charBuf = DFBufferNew();
for (size_t pos = 0; pos < input->len; pos++) {
if ((pos > 0) && (pos % 40 == 0))
DFBufferAppendChar(charBuf,'\n');
unsigned char hi = ((unsigned char *)input->data)[pos] >> 4;
unsigned char lo = ((unsigned char *)input->data)[pos] & 0x0F;
DFBufferAppendChar(charBuf,hexchars[hi]);
DFBufferAppendChar(charBuf,hexchars[lo]);
}
if ((input->len % 40) != 0)
DFBufferAppendChar(charBuf,'\n');
char *result = xstrdup(charBuf->data);
DFBufferRelease(charBuf);
return result;
}
DFBuffer *stringToBinary(const char *str)
{
size_t length = strlen(str);
DFBuffer *outbuf = DFBufferNew();
int wantHi = 1;
unsigned char hi = 0;
for (size_t inpos = 0; inpos < length; inpos++) {
char c = str[inpos];
unsigned char nibble = 0;
if ((c >= '0') && (c <= '9'))
nibble = c - '0';
else if ((c >= 'a') && (c <= 'f'))
nibble = 10 + (c - 'a');
else if ((c >= 'A') && (c <= 'F'))
nibble = 10 + (c - 'A');
else
continue;
if (wantHi)
hi = nibble << 4;
else
DFBufferAppendChar(outbuf,hi | nibble);
wantHi = !wantHi;
}
return outbuf;
}