l10n: Updates to Chinese (Taiwan) (zh_TW) translation
[pulseaudio-mirror.git] / src / pulsecore / mcalign.c
bloba03d5ae79b5a26aa69fefccedad64853ad9ee88a
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <pulse/xmalloc.h>
31 #include <pulsecore/macro.h>
33 #include "mcalign.h"
35 struct pa_mcalign {
36 size_t base;
37 pa_memchunk leftover, current;
40 pa_mcalign *pa_mcalign_new(size_t base) {
41 pa_mcalign *m;
42 pa_assert(base);
44 m = pa_xnew(pa_mcalign, 1);
46 m->base = base;
47 pa_memchunk_reset(&m->leftover);
48 pa_memchunk_reset(&m->current);
50 return m;
53 void pa_mcalign_free(pa_mcalign *m) {
54 pa_assert(m);
56 if (m->leftover.memblock)
57 pa_memblock_unref(m->leftover.memblock);
59 if (m->current.memblock)
60 pa_memblock_unref(m->current.memblock);
62 pa_xfree(m);
65 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
66 pa_assert(m);
67 pa_assert(c);
69 pa_assert(c->memblock);
70 pa_assert(c->length > 0);
72 pa_assert(!m->current.memblock);
74 /* Append to the leftover memory block */
75 if (m->leftover.memblock) {
77 /* Try to merge */
78 if (m->leftover.memblock == c->memblock &&
79 m->leftover.index + m->leftover.length == c->index) {
81 /* Merge */
82 m->leftover.length += c->length;
84 /* If the new chunk is larger than m->base, move it to current */
85 if (m->leftover.length >= m->base) {
86 m->current = m->leftover;
87 pa_memchunk_reset(&m->leftover);
90 } else {
91 size_t l;
92 void *lo_data, *m_data;
94 /* We have to copy */
95 pa_assert(m->leftover.length < m->base);
96 l = m->base - m->leftover.length;
98 if (l > c->length)
99 l = c->length;
101 /* Can we use the current block? */
102 pa_memchunk_make_writable(&m->leftover, m->base);
104 lo_data = pa_memblock_acquire(m->leftover.memblock);
105 m_data = pa_memblock_acquire(c->memblock);
106 memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l);
107 pa_memblock_release(m->leftover.memblock);
108 pa_memblock_release(c->memblock);
109 m->leftover.length += l;
111 pa_assert(m->leftover.length <= m->base);
112 pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
114 if (c->length > l) {
115 /* Save the remainder of the memory block */
116 m->current = *c;
117 m->current.index += l;
118 m->current.length -= l;
119 pa_memblock_ref(m->current.memblock);
122 } else {
123 /* Nothing to merge or copy, just store it */
125 if (c->length >= m->base)
126 m->current = *c;
127 else
128 m->leftover = *c;
130 pa_memblock_ref(c->memblock);
134 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
135 pa_assert(m);
136 pa_assert(c);
138 /* First test if there's a leftover memory block available */
139 if (m->leftover.memblock) {
140 pa_assert(m->leftover.length > 0);
141 pa_assert(m->leftover.length <= m->base);
143 /* The leftover memory block is not yet complete */
144 if (m->leftover.length < m->base)
145 return -1;
147 /* Return the leftover memory block */
148 *c = m->leftover;
149 pa_memchunk_reset(&m->leftover);
151 /* If the current memblock is too small move it the leftover */
152 if (m->current.memblock && m->current.length < m->base) {
153 m->leftover = m->current;
154 pa_memchunk_reset(&m->current);
157 return 0;
160 /* Now let's see if there is other data available */
161 if (m->current.memblock) {
162 size_t l;
163 pa_assert(m->current.length >= m->base);
165 /* The length of the returned memory block */
166 l = m->current.length;
167 l /= m->base;
168 l *= m->base;
169 pa_assert(l > 0);
171 /* Prepare the returned block */
172 *c = m->current;
173 pa_memblock_ref(c->memblock);
174 c->length = l;
176 /* Drop that from the current memory block */
177 pa_assert(l <= m->current.length);
178 m->current.index += l;
179 m->current.length -= l;
181 /* In case the whole block was dropped ... */
182 if (m->current.length == 0)
183 pa_memblock_unref(m->current.memblock);
184 else {
185 /* Move the raimainder to leftover */
186 pa_assert(m->current.length < m->base && !m->leftover.memblock);
188 m->leftover = m->current;
191 pa_memchunk_reset(&m->current);
193 return 0;
196 /* There's simply nothing */
197 return -1;
200 size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
201 pa_assert(m);
202 pa_assert(l > 0);
204 pa_assert(!m->current.memblock);
206 if (m->leftover.memblock)
207 l += m->leftover.length;
209 return (l/m->base)*m->base;
212 void pa_mcalign_flush(pa_mcalign *m) {
213 pa_memchunk chunk;
214 pa_assert(m);
216 while (pa_mcalign_pop(m, &chunk) >= 0)
217 pa_memblock_unref(chunk.memblock);