3 * \author John Hodge (thePowersGang)
10 #include <udi_internal.h>
12 typedef struct sUDI_BufTag
14 struct sUDI_BufTag *Next;
16 struct sUDI_BufSect *Sect;
19 typedef struct sUDI_BufSect
21 struct sUDI_BufSect *Next;
33 tUDI_BufSect *Sections;
38 EXPORT(udi_buf_write);
44 udi_buf_copy_call_t *callback,
52 udi_buf_path_t path_handle
58 // Quick and evil option - allocate temp buffer, udi_buf_read + udi_buf_write
59 void *tmp = malloc(src_len);
60 udi_buf_read(src_buf, src_off, src_len, tmp);
62 void tmp_callback(udi_cb_t *gcb, udi_buf_t *new_buf) {
66 udi_buf_write(tmp_callback, NULL, tmp, src_len, dst_buf, dst_off, dst_len, path_handle);
70 callback(gcb, dst_buf);
74 tUDI_BufSect *UDI_int_BufAddSect(size_t data_len, size_t relofs, tUDI_BufSect **prevptr, const void *data,
75 udi_buf_path_t path_handle
78 const int space_atom = 1<<7;
79 size_t space = (data_len + space_atom-1) & ~(space_atom-1);
80 tUDI_BufSect *newsect = NEW(tUDI_BufSect, + space);
81 newsect->RelOfs = relofs;
82 newsect->Length = data_len;
83 newsect->Space = space_atom;
84 newsect->Data = newsect+1;
86 memset(newsect->Data, 0xFF, data_len);
88 memcpy(newsect->Data, data, data_len);
90 newsect->Next = *prevptr;
92 LOG("@0x%x : %p <= %p+%i", relofs, newsect->Data, data, data_len);
97 udi_buf_t *_udi_buf_allocate(const void *data, udi_size_t length, udi_buf_path_t path_handle)
99 tUDI_BufInt *buf = NEW(tUDI_BufInt,);
100 udi_buf_t *ret = &buf->buf;
103 UDI_int_BufAddSect(length, 0, &buf->Sections, data, path_handle);
105 ret->buf_size = length;
111 * \brief Write to a buffer
112 * \param callback Function to call once the write has completed
113 * \param gcb Control Block
114 * \param src_mem Source Data
115 * \param src_len Length of source data
116 * \param dst_buf Destination buffer
117 * \param dst_off Destination offset in the buffer
118 * \param dst_len Length of area to be replaced
119 * \param path_handle ???
122 udi_buf_write_call_t *callback,
129 udi_buf_path_t path_handle
132 ENTER("psrc_mem isrc_len pdst_buf idst_off idst_len",
133 src_mem, src_len, dst_buf, dst_off, dst_len);
135 tUDI_BufInt *dst = (void*)dst_buf;
137 dst = NEW(tUDI_BufInt,);
141 // Find dst_off segment
142 tUDI_BufSect **prevptr = &dst->Sections;
143 tUDI_BufSect *sect = dst->Sections;
144 for( ; sect; prevptr = §->Next, sect = sect->Next )
146 if(sect->RelOfs >= dst_off)
148 if(sect->RelOfs + sect->Length > dst_off)
150 dst_off -= sect->RelOfs + sect->Length;
153 LOG("sect = %p", sect);
155 // Overwrite MIN(src_len,dst_len) bytes
156 // then delete/append remainder
157 size_t len = MIN(src_len,dst_len);
162 LOG("Overwriting %i bytes", len);
163 // Create new section
164 if( !sect || sect->RelOfs > dst_off ) {
165 size_t newsize = (sect && sect->RelOfs - dst_off < len) ? sect->RelOfs - dst_off : len;
166 sect = UDI_int_BufAddSect(len, dst_off, prevptr, src_mem, path_handle);
169 prevptr = §->Next;
175 LOG("- dst_off = %i, data=%p", dst_off, sect->Data);
177 // Update existing section
178 size_t bytes = MIN(len, sect->Length - dst_off);
179 memcpy(sect->Data + dst_off, src_mem, bytes);
184 if( dst_off == sect->Length )
186 prevptr = §->Next;
194 LOG("Deleting %i bytes at %i", dst_len, dst_off);
195 ASSERT(src_len == 0);
200 dst_buf->buf_size = dst_off;
203 else if( sect->RelOfs > dst_off ) {
204 size_t bytes = MIN(dst_len, sect->RelOfs - dst_off);
206 dst_buf->buf_size -= bytes;
207 sect->RelOfs -= bytes;
209 else if( dst_off == 0 && sect->Length <= dst_len ) {
210 // Remove entire section
211 dst_len -= sect->Length;
212 dst_buf->buf_size -= sect->Length;
213 *prevptr = sect->Next;
219 else if( dst_off + dst_len >= sect->Length ) {
221 size_t bytes = MIN(dst_len, sect->Length - dst_off);
223 dst_buf->buf_size -= bytes;
224 sect->Length -= bytes;
227 prevptr = §->Next;
231 // in-block removal (must be last)
232 ASSERTC(dst_off + dst_len, <, sect->Length);
233 size_t tail = sect->Length - (dst_off + dst_len);
234 memmove(sect->Data+dst_off, sect->Data+dst_off+dst_len, tail);
235 dst_buf->buf_size -= dst_len;
236 sect->Length -= dst_len;
241 else if( src_len > 0 )
243 LOG("Inserting %i bytes", src_len);
244 ASSERT(dst_len == 0);
246 if( !sect || sect->RelOfs > dst_off ) {
247 // Simple: Just add a new section
248 UDI_int_BufAddSect(src_len, dst_off, prevptr, src_mem, path_handle);
249 dst_buf->buf_size += src_len;
251 else if( sect->RelOfs + sect->Length == dst_off ) {
252 // End of block inserts
253 size_t avail = sect->Space - sect->Length;
255 size_t bytes = MIN(avail, src_len);
257 memcpy(sect->Data + sect->Length, src_mem, bytes);
263 UDI_int_BufAddSect(src_len, 0, prevptr, src_mem, path_handle);
265 dst_buf->buf_size += src_len;
268 // Complex: Need to handle mid-section inserts
269 Log_Warning("UDI", "TODO: udi_buf_write - mid-section inserts");
274 LOG("No insert/delete, ovr only");
278 LOG("dst_buf->size = %i", dst->buf.buf_size);
279 LEAVE('p', &dst->buf);
280 // HACK: udi_pio_trans calls this with a NULL cb, so handle that
282 callback(gcb, &dst->buf);
292 ENTER("psrc_buf isrc_off isrc_len pdst_mem",
293 src_buf, src_off, src_len, dst_mem);
294 tUDI_BufInt *src = (void*)src_buf;
296 tUDI_BufSect *sect = src->Sections;
299 for( ; sect; sect = sect->Next )
301 LOG("%x <= %x <= +%x", sect->RelOfs, src_off, sect->Length);
302 if(sect->RelOfs >= src_off)
304 if(sect->RelOfs + sect->Length > src_off)
306 src_off -= sect->RelOfs + sect->Length;
312 if( src_off < sect->RelOfs ) {
313 size_t undef_len = MIN(src_len, sect->RelOfs - src_off);
314 LOG("%i undef", undef_len);
315 memset(dst_mem, 0xFF, undef_len);
316 dst_mem += undef_len;
317 src_len -= undef_len;
318 src_off += undef_len;
322 ASSERTC(src_off, >=, sect->RelOfs);
323 size_t ofs = src_off - sect->RelOfs;
324 size_t len = MIN(src_len, sect->Length - ofs);
325 LOG("%i data from %p + %i", len, sect->Data, ofs);
326 memcpy(dst_mem, sect->Data+ofs, len);
330 src_off -= sect->RelOfs + sect->Length;
336 void udi_buf_free(udi_buf_t *buf_ptr)
340 tUDI_BufInt *buf = (void*)buf_ptr;
344 tUDI_BufTag *tag = buf->Tags;
345 buf->Tags = tag->Next;
350 while( buf->Sections )
352 tUDI_BufSect *sect = buf->Sections;
353 buf->Sections = sect->Next;