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// for malloc() & free()
30#include <stdlib.h>
31// for memcpy()
32#include <string.h>
33
34#include "deblock_media.h"
35
36
37/*
38 * Defines
39 */
40
41
42/*
43 * Types
44 */
45typedef struct deblock_media *DEBLOCK_MEDIA;
46
47struct deblock_media {
48    struct media    m;
49    long            need_filtering;
50    MEDIA           next_media;
51    unsigned long   next_block_size;
52    unsigned char   *buffer;
53};
54
55struct deblock_globals {
56    long        exists;
57    long        kind;
58};
59
60
61/*
62 * Global Constants
63 */
64
65
66/*
67 * Global Variables
68 */
69static long deblock_inited = 0;
70static struct deblock_globals deblock_info;
71
72/*
73 * Forward declarations
74 */
75void deblock_init(void);
76DEBLOCK_MEDIA new_deblock_media(void);
77long read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
78long write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
79long close_deblock_media(MEDIA m);
80long os_reload_deblock_media(MEDIA m);
81
82
83/*
84 * Routines
85 */
86void
87deblock_init(void)
88{
89    if (deblock_inited != 0) {
90	return;
91    }
92    deblock_inited = 1;
93
94    deblock_info.kind = allocate_media_kind();
95}
96
97
98DEBLOCK_MEDIA
99new_deblock_media(void)
100{
101    return (DEBLOCK_MEDIA) new_media(sizeof(struct deblock_media));
102}
103
104
105MEDIA
106open_deblock_media(unsigned long new_block_size, MEDIA m)
107{
108    DEBLOCK_MEDIA   a;
109    unsigned long   block_size;
110
111    if (deblock_inited == 0) {
112	deblock_init();
113    }
114
115    a = 0;
116    if (m != 0) {
117	block_size = media_granularity(m);
118
119	if (new_block_size == block_size) {
120	    return m;
121
122	} else if (new_block_size > block_size) {
123	    if ((new_block_size % block_size) == 0) {
124		/* no filtering necessary */
125		a = new_deblock_media();
126		if (a != 0) {
127		    a->need_filtering = 0;
128		    a->next_block_size = block_size;
129		    a->buffer = 0;
130		}
131	    } else {
132		/* too hard to bother with */
133	    }
134	} else /* new_block_size < block_size */ {
135	    if ((block_size % new_block_size) == 0) {
136		/* block & unblock */
137		a = new_deblock_media();
138		if (a != 0) {
139		    a->need_filtering = 1;
140		    a->next_block_size = block_size;
141		    a->buffer = malloc(block_size);
142		}
143	    } else {
144		/* too hard to bother with */
145	    }
146	}
147	if (a != 0) {
148	    a->m.kind = deblock_info.kind;
149	    a->m.grain = new_block_size;
150	    a->m.size_in_bytes = media_total_size(m);
151	    a->m.do_read = read_deblock_media;
152	    a->m.do_write = write_deblock_media;
153	    a->m.do_close = close_deblock_media;
154	    a->m.do_os_reload = os_reload_deblock_media;
155	    a->next_media = m;
156	}
157    }
158    return (MEDIA) a;
159}
160
161
162long
163read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
164{
165    DEBLOCK_MEDIA a;
166    long rtn_value;
167    unsigned long next_size;
168    unsigned long partial_offset;
169    unsigned long partial_count;
170    long long cur_offset;
171    unsigned long remainder;
172    unsigned char *addr;
173
174    a = (DEBLOCK_MEDIA) m;
175    rtn_value = 0;
176    if (a == 0) {
177	/* no media */
178    } else if (a->m.kind != deblock_info.kind) {
179	/* wrong kind - XXX need to error here - this is an internal problem */
180    } else if (count <= 0 || count % a->m.grain != 0) {
181	/* can't handle size */
182    } else if (offset < 0 || offset % a->m.grain != 0) {
183	/* can't handle offset */
184    } else if (a->need_filtering == 0) {
185	rtn_value = read_media(a->next_media, offset, count, address);
186    } else {
187	next_size = a->next_block_size;
188	addr = address;
189	cur_offset = offset;
190	remainder = count;
191	rtn_value = 1;
192
193	/* read partial */
194	partial_offset = cur_offset % next_size;
195	if (partial_offset != 0) {
196	    partial_count = next_size - partial_offset;
197	    if (partial_count > remainder) {
198		partial_count = remainder;
199	    }
200	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
201	    if (rtn_value != 0) {
202		memcpy (addr, a->buffer + partial_offset, partial_count);
203		addr += partial_count;
204		cur_offset += partial_count;
205		remainder -= partial_count;
206	    }
207	}
208	/* read fulls as long as needed */
209	if (rtn_value != 0 && remainder > next_size) {
210	    partial_count = remainder - (remainder % next_size);
211	    rtn_value = read_media(a->next_media, cur_offset, partial_count, addr);
212	    addr += partial_count;
213	    cur_offset += partial_count;
214	    remainder -= partial_count;
215	}
216	/* read partial */
217	if (rtn_value != 0 && remainder > 0) {
218	    partial_count = remainder;
219	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
220	    if (rtn_value != 0) {
221		memcpy (addr, a->buffer, partial_count);
222	    }
223	}
224    }
225    return rtn_value;
226}
227
228
229long
230write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
231{
232    DEBLOCK_MEDIA a;
233    long rtn_value;
234    unsigned long next_size;
235    unsigned long partial_offset;
236    unsigned long partial_count;
237    long long cur_offset;
238    unsigned long remainder;
239    unsigned char *addr;
240
241    a = (DEBLOCK_MEDIA) m;
242    rtn_value = 0;
243    if (a == 0) {
244	/* no media */
245    } else if (a->m.kind != deblock_info.kind) {
246	/* wrong kind - XXX need to error here - this is an internal problem */
247    } else if (count <= 0 || count % a->m.grain != 0) {
248	/* can't handle size */
249    } else if (offset < 0 || offset % a->m.grain != 0) {
250	/* can't handle offset */
251    } else if (a->need_filtering == 0) {
252	rtn_value = write_media(a->next_media, offset, count, address);
253    } else {
254	next_size = a->next_block_size;
255	addr = address;
256	cur_offset = offset;
257	remainder = count;
258	rtn_value = 1;
259
260	/* write partial */
261	partial_offset = cur_offset % next_size;
262	if (partial_offset != 0) {
263	    partial_count = next_size - partial_offset;
264	    if (partial_count > remainder) {
265		partial_count = remainder;
266	    }
267	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
268	    if (rtn_value != 0) {
269		memcpy (a->buffer + partial_offset, addr, partial_count);
270		rtn_value = write_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
271		addr += partial_count;
272		cur_offset += partial_count;
273		remainder -= partial_count;
274	    }
275	}
276	/* write fulls as long as needed */
277	if (rtn_value != 0 && remainder > next_size) {
278	    partial_count = remainder - (remainder % next_size);
279	    rtn_value = write_media(a->next_media, cur_offset, partial_count, addr);
280	    addr += partial_count;
281	    cur_offset += partial_count;
282	    remainder -= partial_count;
283	}
284	/* write partial */
285	if (rtn_value != 0 && remainder > 0) {
286	    partial_count = remainder;
287	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
288	    if (rtn_value != 0) {
289		memcpy (a->buffer, addr, partial_count);
290		rtn_value = write_media(a->next_media, cur_offset, next_size, a->buffer);
291	    }
292	}
293    }
294    /* recompute size to handle file media */
295    a->m.size_in_bytes = media_total_size(a->next_media);
296    return rtn_value;
297}
298
299
300long
301close_deblock_media(MEDIA m)
302{
303    DEBLOCK_MEDIA a;
304
305    a = (DEBLOCK_MEDIA) m;
306    if (a == 0) {
307	return 0;
308    } else if (a->m.kind != deblock_info.kind) {
309	/* XXX need to error here - this is an internal problem */
310	return 0;
311    }
312
313    close_media(a->next_media);
314    free(a->buffer);
315    return 1;
316}
317
318
319long
320os_reload_deblock_media(MEDIA m)
321{
322    DEBLOCK_MEDIA a;
323
324    a = (DEBLOCK_MEDIA) m;
325    if (a == 0) {
326	return 0;
327    } else if (a->m.kind != deblock_info.kind) {
328	/* XXX need to error here - this is an internal problem */
329	return 0;
330    }
331
332    os_reload_media(a->next_media);
333    return 1;
334}
335