1/*
2 * deblock_media.c -
3 *
4 * Written by Eryk Vershen
5 */
6
7/*
8 * Copyright 1997,1998 by Apple Computer, Inc.
9 *              All Rights Reserved
10 *
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both the copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE.
20 *
21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 */
27
28
29#include <stdio.h>
30// for malloc() & free()
31#include <stdlib.h>
32// for memcpy()
33#include <string.h>
34
35#include "deblock_media.h"
36
37
38/*
39 * Defines
40 */
41
42
43/*
44 * Types
45 */
46typedef struct deblock_media *DEBLOCK_MEDIA;
47
48struct deblock_media {
49    struct media    m;
50    long            need_filtering;
51    MEDIA           next_media;
52    uint32_t   next_block_size;
53    uint8_t   *buffer;
54};
55
56struct deblock_globals {
57    long        exists;
58    long        kind;
59};
60
61
62/*
63 * Global Constants
64 */
65
66
67/*
68 * Global Variables
69 */
70static long deblock_inited = 0;
71static struct deblock_globals deblock_info;
72
73/*
74 * Forward declarations
75 */
76void deblock_init(void);
77DEBLOCK_MEDIA new_deblock_media(void);
78long read_deblock_media(MEDIA m, long long offset, uint32_t count, void *address);
79long write_deblock_media(MEDIA m, long long offset, uint32_t count, void *address);
80long close_deblock_media(MEDIA m);
81long os_reload_deblock_media(MEDIA m);
82
83
84/*
85 * Routines
86 */
87void
88deblock_init(void)
89{
90    if (deblock_inited != 0) {
91	return;
92    }
93    deblock_inited = 1;
94
95    deblock_info.kind = allocate_media_kind();
96}
97
98
99DEBLOCK_MEDIA
100new_deblock_media(void)
101{
102    return (DEBLOCK_MEDIA) new_media(sizeof(struct deblock_media));
103}
104
105
106MEDIA
107open_deblock_media(uint32_t new_block_size, MEDIA m)
108{
109    DEBLOCK_MEDIA   a;
110    uint32_t block_size;
111
112    if (deblock_inited == 0) {
113	deblock_init();
114    }
115
116    a = 0;
117    if (m != 0) {
118	block_size = media_granularity(m);
119
120	if (new_block_size == block_size) {
121	    return m;
122
123	} else if (new_block_size > block_size) {
124	    if ((new_block_size % block_size) == 0) {
125		/* no filtering necessary */
126		a = new_deblock_media();
127		if (a != 0) {
128		    a->need_filtering = 0;
129		    a->next_block_size = block_size;
130		    a->buffer = 0;
131		}
132	    } else {
133		/* too hard to bother with */
134	    }
135	} else /* new_block_size < block_size */ {
136	    if ((block_size % new_block_size) == 0) {
137		/* block & unblock */
138		a = new_deblock_media();
139		if (a != 0) {
140		    a->need_filtering = 1;
141		    a->next_block_size = block_size;
142		    a->buffer = malloc(block_size);
143		}
144	    } else {
145		/* too hard to bother with */
146	    }
147	}
148	if (a != 0) {
149	    a->m.kind = deblock_info.kind;
150	    a->m.grain = new_block_size;
151	    a->m.size_in_bytes = media_total_size(m);
152	    a->m.do_read = read_deblock_media;
153	    a->m.do_write = write_deblock_media;
154	    a->m.do_close = close_deblock_media;
155	    a->m.do_os_reload = os_reload_deblock_media;
156	    a->next_media = m;
157	}
158    }
159    return (MEDIA) a;
160}
161
162
163long
164read_deblock_media(MEDIA m, long long offset, uint32_t count, void *address)
165{
166    DEBLOCK_MEDIA a;
167    long rtn_value;
168    uint32_t next_size;
169    uint32_t partial_offset;
170    uint32_t partial_count;
171    long long cur_offset;
172    uint32_t remainder;
173    uint8_t *addr;
174
175    a = (DEBLOCK_MEDIA) m;
176    rtn_value = 0;
177    if (a == 0) {
178	/* no media */
179    } else if (a->m.kind != deblock_info.kind) {
180	/* wrong kind - XXX need to error here - this is an internal problem */
181    } else if (count <= 0 || count % a->m.grain != 0) {
182	/* can't handle size */
183    } else if (offset < 0 || offset % a->m.grain != 0) {
184	/* can't handle offset */
185    } else if (a->need_filtering == 0) {
186	rtn_value = read_media(a->next_media, offset, count, address);
187    } else {
188	next_size = a->next_block_size;
189	addr = address;
190	cur_offset = offset;
191	remainder = count;
192	rtn_value = 1;
193
194	/* read partial */
195	partial_offset = cur_offset % next_size;
196	if (partial_offset != 0) {
197	    partial_count = next_size - partial_offset;
198	    if (partial_count > remainder) {
199		partial_count = remainder;
200	    }
201	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
202	    if (rtn_value != 0) {
203		memcpy (addr, a->buffer + partial_offset, partial_count);
204		addr += partial_count;
205		cur_offset += partial_count;
206		remainder -= partial_count;
207	    }
208	}
209	/* read fulls as long as needed */
210	if (rtn_value != 0 && remainder > next_size) {
211	    partial_count = remainder - (remainder % next_size);
212	    rtn_value = read_media(a->next_media, cur_offset, partial_count, addr);
213	    addr += partial_count;
214	    cur_offset += partial_count;
215	    remainder -= partial_count;
216	}
217	/* read partial */
218	if (rtn_value != 0 && remainder > 0) {
219	    partial_count = remainder;
220	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
221	    if (rtn_value != 0) {
222		memcpy (addr, a->buffer, partial_count);
223	    }
224	}
225    }
226    return rtn_value;
227}
228
229
230long
231write_deblock_media(MEDIA m, long long offset, uint32_t count, void *address)
232{
233    DEBLOCK_MEDIA a;
234    long rtn_value;
235    uint32_t next_size;
236    uint32_t partial_offset;
237    uint32_t partial_count;
238    long long cur_offset;
239    uint32_t remainder;
240    uint8_t *addr;
241
242    a = (DEBLOCK_MEDIA) m;
243    rtn_value = 0;
244    if (a == 0) {
245	/* no media */
246    } else if (a->m.kind != deblock_info.kind) {
247	/* wrong kind - XXX need to error here - this is an internal problem */
248    } else if (count <= 0 || count % a->m.grain != 0) {
249	/* can't handle size */
250    } else if (offset < 0 || offset % a->m.grain != 0) {
251	/* can't handle offset */
252    } else if (a->need_filtering == 0) {
253	rtn_value = write_media(a->next_media, offset, count, address);
254    } else {
255	next_size = a->next_block_size;
256	addr = address;
257	cur_offset = offset;
258	remainder = count;
259	rtn_value = 1;
260
261	/* write partial */
262	partial_offset = cur_offset % next_size;
263	if (partial_offset != 0) {
264	    partial_count = next_size - partial_offset;
265	    if (partial_count > remainder) {
266		partial_count = remainder;
267	    }
268	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
269	    if (rtn_value != 0) {
270		memcpy (a->buffer + partial_offset, addr, partial_count);
271		rtn_value = write_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
272		addr += partial_count;
273		cur_offset += partial_count;
274		remainder -= partial_count;
275	    }
276	}
277	/* write fulls as long as needed */
278	if (rtn_value != 0 && remainder > next_size) {
279	    partial_count = remainder - (remainder % next_size);
280	    rtn_value = write_media(a->next_media, cur_offset, partial_count, addr);
281	    addr += partial_count;
282	    cur_offset += partial_count;
283	    remainder -= partial_count;
284	}
285	/* write partial */
286	if (rtn_value != 0 && remainder > 0) {
287	    partial_count = remainder;
288	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
289	    if (rtn_value != 0) {
290		memcpy (a->buffer, addr, partial_count);
291		rtn_value = write_media(a->next_media, cur_offset, next_size, a->buffer);
292	    }
293	}
294    }
295    /* recompute size to handle file media */
296    a->m.size_in_bytes = media_total_size(a->next_media);
297    return rtn_value;
298}
299
300
301long
302close_deblock_media(MEDIA m)
303{
304    DEBLOCK_MEDIA a;
305
306    a = (DEBLOCK_MEDIA) m;
307    if (a == 0) {
308	return 0;
309    } else if (a->m.kind != deblock_info.kind) {
310	/* XXX need to error here - this is an internal problem */
311	return 0;
312    }
313
314    close_media(a->next_media);
315    free(a->buffer);
316    return 1;
317}
318
319
320long
321os_reload_deblock_media(MEDIA m)
322{
323    DEBLOCK_MEDIA a;
324
325    a = (DEBLOCK_MEDIA) m;
326    if (a == 0) {
327	return 0;
328    } else if (a->m.kind != deblock_info.kind) {
329	/* XXX need to error here - this is an internal problem */
330	return 0;
331    }
332
333    os_reload_media(a->next_media);
334    return 1;
335}
336