| // 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; |
| } |