001    /*
002     * Copyright (c) Andrey Kuznetsov. All Rights Reserved.
003     *
004     * http://uio.imagero.com
005     *
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions are met:
008     *
009     *  o Redistributions of source code must retain the above copyright notice,
010     *    this list of conditions and the following disclaimer.
011     *
012     *  o Redistributions in binary form must reproduce the above copyright notice,
013     *    this list of conditions and the following disclaimer in the documentation
014     *    and/or other materials provided with the distribution.
015     *
016     *  o Neither the name of Andrey Kuznetsov nor the names of
017     *    its contributors may be used to endorse or promote products derived
018     *    from this software without specific prior written permission.
019     *
020     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
029     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
030     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031     */
032    package com.imagero.uio.bio.content;
033    
034    import com.imagero.uio.Transformer;
035    
036    import java.io.IOException;
037    
038    /**
039     * Date: 05.01.2008
040     *
041     * @author Andrey Kuznetsov
042     */
043    public class CharArrayContent extends Content {
044        char[][] data;
045        boolean bigEndian;
046    
047        static final int SHIFT = 1;
048    
049        public CharArrayContent(char[][] data) {
050            this(data, true);
051        }
052    
053        public CharArrayContent(char[][] data, boolean bigEndian) {
054            this.data = data;
055            this.bigEndian = bigEndian;
056        }
057    
058        public int load(long offset, int bpos, byte[] dest) throws IOException {
059            //to simplify char to byte converting, we require two bytes boundary
060            if ((offset & 1) != 0 || ((dest.length - bpos) & 1) != 0) {
061                throw new IOException("Illegal offset or length");
062            }
063            final long off = offset >> SHIFT;
064            final int len = (dest.length - bpos) >> SHIFT;
065    
066            IndexAndStart ias = getIAS(off);
067            if (ias == null) {
068                return 0;
069            }
070            int index = ias.index;
071            int pos = (int) (off - ias.start);
072            char[] src = data[index];
073            int toCopy = Math.min(src.length - pos, len);
074            if (toCopy > 0) {
075                com.imagero.uio.Transformer.charToByte(src, pos, toCopy, dest, bpos, bigEndian);
076                if ((toCopy < len)) {
077                    int copiedBytes = (toCopy << SHIFT);
078                    return toCopy + load(offset + copiedBytes, bpos + copiedBytes, dest);
079                }
080            }
081            return toCopy;
082        }
083    
084        public void close() {
085        }
086    
087        private IndexAndStart getIAS(long offset) {
088            long start = 0;
089            for (int i = 0; i < data.length; i++) {
090                char[] src = data[i];
091                int length = src.length;
092                long end = start + length;
093                if (offset >= start && offset <= end) {
094                    return new IndexAndStart(i, start);
095                }
096                start += length;
097            }
098            return null;
099        }
100    
101        /**
102         * Save data to current content (char array).
103         * All offsets and lengths must be
104         * @param offset
105         * @param spos
106         * @param src
107         * @param length
108         * @throws IOException
109         */
110        public void save(long offset, int spos, byte[] src, int length) throws IOException {
111            //to simplify char to byte converting we require two byte boundary
112            if ((offset & 1) != 0 || ((src.length - spos) & 1) != 0) {
113                throw new IOException("Illegal offset or length");
114            }
115            final long off = offset >> SHIFT;
116            final int len = Math.min((src.length - spos), length) >> SHIFT;
117    
118            IndexAndStart ias = getIAS(off);
119            if (ias == null) {
120                return;
121            }
122            int index = ias.index;
123            long start = ias.start;
124            int dpos = (int) (off - start);
125            char[] dest = data[index];
126            int request = len;
127            int toCopy = Math.min((dest.length - dpos), request);
128            if (request > 0 && toCopy > 0) {
129                com.imagero.uio.Transformer.byteToChar(src, spos, toCopy, dest, dpos, true);
130                if (toCopy < request) {
131                    int copiedBytes = (toCopy << SHIFT);
132                    save(offset + copiedBytes, spos + copiedBytes, src, (request - toCopy) << SHIFT);
133                }
134            }
135        }
136    
137        public boolean canReload() {
138            return true;
139        }
140    
141        public long length() throws IOException {
142            long length = 0;
143            for (int i = 0; i < data.length; i++) {
144                char[] dest = data[i];
145                length += dest.length;
146            }
147            return length << SHIFT;
148        }
149    
150        public boolean writable() {
151            return true;
152        }
153    }