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    
033    package com.imagero.uio.io;
034    
035    import com.imagero.uio.RandomAccessInput;
036    import com.imagero.uio.Sys;
037    import com.imagero.uio.RandomAccessOutput;
038    import com.imagero.uio.RandomAccessIO;
039    
040    import java.io.BufferedReader;
041    import java.io.BufferedWriter;
042    import java.io.DataInput;
043    import java.io.DataOutput;
044    import java.io.File;
045    import java.io.FileInputStream;
046    import java.io.FileOutputStream;
047    import java.io.IOException;
048    import java.io.InputStream;
049    import java.io.OutputStream;
050    import java.io.RandomAccessFile;
051    
052    /**
053     * IOutils.java
054     *
055     * @author Andrei Kouznetsov
056     */
057    public class IOutils {
058        private static final int BIG_ENDIAN = 0x4D4D;
059        private static final int LITTLE_ENDIAN = 0x4949;
060    
061        /**
062         * close silently stream<br>
063         * no exception it thrown
064         *
065         * @param bw
066         */
067        public static void closeStream(BufferedWriter bw) {
068            try {
069                if (bw != null) {
070                    bw.close();
071                }
072            } catch (IOException ex) {
073            }
074        }
075    
076        /**
077         * close silently stream<br>
078         * no exception it thrown
079         *
080         * @param br
081         */
082        public static void closeStream(BufferedReader br) {
083            try {
084                if (br != null) {
085                    br.close();
086                }
087            } catch (IOException ex) {
088            }
089        }
090    
091        /**
092         * close silently stream<br>
093         * no exception it thrown
094         *
095         * @param is
096         */
097        public static void closeStream(InputStream is) {
098            try {
099                if (is != null) {
100                    is.close();
101                }
102            } catch (IOException ex) {
103            }
104        }
105    
106        /**
107         * close silently stream<br>
108         * no exception it thrown
109         *
110         * @param os
111         */
112        public static void closeStream(OutputStream os) {
113            try {
114                if (os != null) {
115                    os.close();
116                }
117            } catch (IOException ex) {
118            }
119        }
120    
121        /**
122         * close silently stream<br>
123         * no exception it thrown
124         *
125         * @param raf
126         */
127        public static void closeStream(RandomAccessFile raf) {
128            try {
129                if (raf != null) {
130                    raf.close();
131                }
132            } catch (IOException ex) {
133            }
134        }
135    
136        /**
137         * close silently stream<br>
138         * no exception it thrown
139         *
140         * @param ro
141         */
142        public static void closeStream(RandomAccessInput ro) {
143            try {
144                if (ro != null) {
145                    ro.close();
146                }
147            } catch (IOException ex) {
148            }
149        }
150    
151        public static void closeStream(RandomAccessOutput ro) {
152            try {
153                if (ro != null) {
154                    ro.close();
155                }
156            } catch (IOException ex) {
157            }
158        }
159    
160        public static void closeStream(RandomAccessIO ro) {
161            try {
162                if (ro != null) {
163                    ro.close();
164                }
165            } catch (IOException ex) {
166            }
167        }
168    
169        static final int[] mask = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
170        static byte b0 = (byte) '0';
171        static byte b1 = (byte) '1';
172    
173        public static String toBinaryString(byte value) {
174            byte[] b = new byte[8];
175            int cnt = 0;
176            for (int i = 7; i > -1; i--) {
177                b[cnt++] = (value & mask[i]) == 0 ? b0 : b1;
178            }
179            return new String(b);
180        }
181    
182        public static String toBinaryString(char value) {
183            byte[] b = new byte[16];
184            int cnt = 0;
185            for (int i = 15; i > -1; i--) {
186                b[cnt++] = (value & mask[i]) == 0 ? b0 : b1;
187            }
188            return new String(b);
189        }
190    
191        public static String toBinaryString(int value, int length) {
192            byte[] b = new byte[length];
193            int cnt = 0;
194            for (int i = length - 1; i > -1; i--) {
195                if (((value >> i) & 1) == 1) {
196                    b[cnt++] = b1;
197                } else {
198                    b[cnt++] = b0;
199                }
200            }
201            return new String(b);
202        }
203    
204        final static byte[] digits = {
205            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
206            (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
207            (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
208        };
209    
210        public static String toHexString(byte value) {
211            return toUnsignedString(value & 0xFF, 4);
212        }
213    
214        private static String toUnsignedString(int i, int shift) {
215            byte[] buf = new byte[]{(byte) '0', (byte) '0'};
216            int charPos = 2;
217            int radix = 1 << shift;
218            int mask = radix - 1;
219            do {
220                buf[--charPos] = digits[i & mask];
221                i >>>= shift;
222            } while (i != 0);
223    
224            return new String(buf);
225        }
226    
227        public static void printHexByte(int value) {
228            printHexImpl(value & 0xFFFF, 2);
229        }
230    
231        public static void printlnHexByte(int value) {
232            printHexImpl(value & 0xFFFF, 2);
233            Sys.out.println("");
234        }
235    
236        public static void printHexShort(int value) {
237            printHexImpl(value & 0xFFFF, 4);
238        }
239    
240        public static void printlnHexShort(int value) {
241            printHexImpl(value & 0xFFFF, 4);
242            Sys.out.println("");
243        }
244    
245        public static void printHexInt(int value) {
246            printHexImpl(value & 0xFFFFFFFF, 8);
247        }
248    
249        public static void printlnHexInt(int value) {
250            printHexImpl(value & 0xFFFFFFFF, 8);
251            Sys.out.println("");
252        }
253    
254        public static void printHexLong(long value) {
255            printHexImpl(value & 0xFFFFFFFFFFFFFFFFL, 16);
256        }
257    
258        public static void printlnHexLong(long value) {
259            printHexImpl(value & 0xFFFFFFFFFFFFFFFFL, 16);
260            Sys.out.println("");
261        }
262    
263        static void printHexImpl(long value, int length) {
264            String s = Long.toHexString(value);
265            //Sys.out.println("***********************" + s + " " + value);
266            for (int i = 0, size = length - s.length(); i < size; i++) {
267                Sys.out.print("0");
268            }
269            Sys.out.print(s);
270        }
271    
272        static void printHexImpl(int value, int length) {
273            String s = Integer.toHexString(value);
274            if (s.length() > length) {
275                s = s.substring(s.length() - length);
276            }
277            //Sys.out.println("***********************" + s + " " + value);
278            for (int i = 0, size = length - s.length(); i < size; i++) {
279                Sys.out.print("0");
280            }
281            Sys.out.print(s);
282        }
283    
284        public static String getExtension(File f) {
285            String s = f.getName();
286            return s.substring(s.lastIndexOf(".") + 1).toUpperCase();
287        }
288    
289        /**
290         * read little-endian short
291         */
292        public static int readShort4D(InputStream in) throws IOException {
293            return ((in.read() & 0xFF) << 8) + ((in.read() & 0xFF) << 0);
294        }
295    
296        /**
297         * read little-endian short
298         */
299        public static int readShort4D(DataInput in) throws IOException {
300            return ((in.readByte() & 0xFF) << 8) + ((in.readByte() & 0xFF) << 0);
301        }
302    
303        /**
304         * read big-endian short
305         */
306        public static int readShort49(InputStream in) throws IOException {
307            return ((in.read() & 0xFF) << 0) + ((in.read() & 0xFF) << 8);
308        }
309    
310        /**
311         * read big-endian short
312         */
313        public static int readShort49(DataInput in) throws IOException {
314            return ((in.readByte() & 0xFF) << 0) + ((in.readByte() & 0xFF) << 8);
315        }
316    
317        /**
318         * read little-endian int
319         */
320        public static int readInt4D(InputStream in) throws IOException {
321            return (((in.read() & 0xFF) << 24) + ((in.read() & 0xFF) << 16) + ((in.read() & 0xFF) << 8) + ((in.read() & 0xFF) << 0));
322        }
323    
324        /**
325         * read big-endian int
326         */
327        public static int readInt4D(DataInput in) throws IOException {
328            int b0 = (in.readByte() & 0xFF);
329            int b1 = (in.readByte() & 0xFF);
330            int b2 = (in.readByte() & 0xFF);
331            int b3 = (in.readByte() & 0xFF);
332            return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
333        }
334    
335        /**
336         * read big-endian int
337         */
338        public static int readInt49(InputStream in) throws IOException {
339            return ((in.read() & 0xFF) << 0) + ((in.read() & 0xFF) << 8) + ((in.read() & 0xFF) << 16) + ((in.read() & 0xFF) << 24);
340        }
341    
342        /**
343         * read big-endian int
344         */
345        public static int readInt49(DataInput in) throws IOException {
346            return ((in.readByte() & 0xFF) << 0) + ((in.readByte() & 0xFF) << 8) + ((in.readByte() & 0xFF) << 16) + ((in.readByte() & 0xFF) << 24);
347        }
348    
349        /**
350         * read little-endian long
351         */
352        public static long readLong4D(InputStream in) throws IOException {
353            return ((long) (readInt4D(in)) << 32) + (readInt4D(in) & 0xFFFFFFFFL);
354        }
355    
356        /**
357         * read little-endian long
358         */
359        public static long readLong4D(DataInput in) throws IOException {
360            return ((long) (readInt4D(in)) << 32) + (readInt4D(in) & 0xFFFFFFFFL);
361        }
362    
363        /**
364         * read big-endian long
365         */
366        public static long readLong49(InputStream in) throws IOException {
367            return ((long) (readInt49(in)) & 0xFFFFFFFFL) + (readInt49(in) << 32);
368        }
369    
370        /**
371         * read big-endian long
372         */
373        public static long readLong49(DataInput in) throws IOException {
374            return ((long) (readInt49(in)) & 0xFFFFFFFFL) + (readInt49(in) << 32);
375        }
376    
377        public static byte readSByte(DataInput ro) throws IOException {
378            byte b = ro.readByte();
379            if (b < 0) {
380                b = (byte) -(~(b + 1));
381            }
382            return b;
383        }
384    
385        public static short readSShort(DataInput ro) throws IOException {
386            short b = ro.readShort();
387            if (b < 0) {
388                b = (short) -(~(b + 1));
389            }
390            return b;
391        }
392    
393        public static int readSInt(DataInput ro) throws IOException {
394            int b = ro.readInt();
395            if (b < 0) {
396                b = -(~(b + 1));
397            }
398            return b;
399        }
400    
401        public static long readSLong(DataInput ro) throws IOException {
402            long b = ro.readLong();
403            if (b < 0) {
404                b = -(~(b + 1));
405            }
406            return b;
407        }
408    
409        /**
410         * Read byte array and convert from 2's complement
411         * @param ro RandomAccessRO
412         * @param b0 byte array
413         * @throws IOException
414         */
415        public static void readFullyS(DataInput ro, byte[] b0) throws IOException {
416            ro.readFully(b0);
417            convertFrom2C(b0);
418        }
419    
420        /**
421         * Convert byte array from 2's complement
422         */
423        public static final void convertFrom2C(byte[] b0) {
424            for (int i = 0; i < b0.length; i++) {
425                if (b0[i] < 0) {
426                    b0[i] = (byte) -(~(b0[i] + 1));
427                }
428            }
429        }
430    
431        /**
432         * Read short array and convert from 2's complement.
433         * @param ro RandomAccessRO
434         * @param b0 short array
435         * @throws IOException
436         */
437        public static void readFullyS(RandomAccessInput ro, short[] b0) throws IOException {
438            ro.readFully(b0);
439            convertFrom2C(b0);
440        }
441    
442        /**
443         * Convert short array from 2's complement
444         */
445        public static final void convertFrom2C(short[] b0) {
446            for (int i = 0; i < b0.length; i++) {
447                if (b0[i] < 0) {
448                    b0[i] = (short) -(~(b0[i] + 1));
449                }
450            }
451        }
452    
453        /**
454         * Read int array and convert from 2's complement
455         * @param ro RandomAccessRO
456         * @param b0 int array
457         * @throws IOException
458         */
459        public static void readFullyS(RandomAccessInput ro, int[] b0) throws IOException {
460            ro.readFully(b0);
461            convertFrom2C(b0);
462        }
463    
464        /**
465         * Convert int array from 2's complement
466         */
467        public static final void convertFrom2C(int[] b0) {
468            for (int i = 0; i < b0.length; i++) {
469                if (b0[i] < 0) {
470                    b0[i] = -(~(b0[i] + 1));
471                }
472            }
473        }
474    
475        /**
476         * Read short array and convert from 2's complement
477         * @param ro RandomAccessRO
478         * @param b0 long array
479         * @throws IOException
480         */
481        public static void readFullyS(RandomAccessInput ro, long[] b0) throws IOException {
482            ro.readFully(b0);
483            convertFrom2C(b0);
484        }
485    
486        /**
487         * Convert long array from 2's complement
488         */
489        public static final void convertFrom2C(long[] b0) {
490            for (int i = 0; i < b0.length; i++) {
491                if (b0[i] < 0) {
492                    b0[i] = -(~(b0[i] + 1));
493                }
494            }
495        }
496    
497        public static void readFully(InputStream in, byte b[]) throws UnexpectedEOFException, IOException {
498            readFully(in, b, 0, b.length);
499        }
500    
501        public static void readFully(InputStream in, byte b[], int off, int len) throws UnexpectedEOFException, IOException {
502            int n = 0;
503            do {
504                int count = in.read(b, off + n, len - n);
505                if (count < 0) {
506                    throw new UnexpectedEOFException(n > 0 ? n : -1);
507    //                              return;
508                }
509                n += count;
510            } while (n < len);
511        }
512    
513        /**
514         * this method is like readFully, but instead of throwing <code>EOFException</code> it returns count of read bytes
515         *
516         * @param in InputStream to read
517         * @param b  byte array to fill
518         *
519         * @return number of bytes read into the buffer, or -1 if EOF was reached
520         *
521         * @throws IOException
522         *
523         */
524        public static int readFully2(InputStream in, byte b[]) throws IOException {
525            return readFully2(in, b, 0, b.length);
526        }
527    
528        /**
529         * this method is like readFully, but instead of throwing <code>EOFException</code> it returns count of read bytes
530         *
531         * @param in  InputStream to read
532         * @param b   byte array to fill
533         * @param off start offset in byte array
534         * @param len number of bytes to read
535         *
536         * @return number of bytes read into the buffer, or -1 if EOF was reached
537         *
538         * @throws IOException
539         */
540        public static int readFully2(InputStream in, byte b[], int off, int len) throws IOException {
541            int n = 0;
542            int cnt0 = 0;
543            do {
544                int count = in.read(b, off + n, len - n);
545                if (count == 0) {
546                    cnt0++;
547                    if (cnt0 >= 3) {
548                        break;
549                    }
550                } else {
551                    cnt0 = 0;
552                }
553                if (count < 0) {
554                    return n == 0 ? -1 : n;
555                }
556                n += count;
557            } while (n < len);
558            return n;
559        }
560    
561        /**
562         * copy <code>length</code> bytes from <code>in</code> to <code>out</code>
563         * @param length amount of bytes to copy
564         * @param in source InputStream
565         * @param out destination OutputStream
566         * @throws IOException
567         */
568        public static long copy(long length, InputStream in, OutputStream out) throws IOException {
569            long copy = 0;
570            byte[] buffer = new byte[2048];
571            while (length > 0) {
572                int read = in.read(buffer, 0, (int) Math.min(buffer.length, length));
573                if (read <= 0) {
574                    break;
575                }
576                copy += read;
577                length -= read;
578                out.write(buffer, 0, read);
579            }
580            return copy;
581        }
582    
583        /**
584         * copy <code>length</code> bytes from source to destination stream
585         * @param length amount of bytes to copy
586         * @param in source stream
587         * @param out destination stream
588         * @throws IOException
589         */
590        public static long copy(long length, InputStream in, DataOutput out) throws IOException {
591            long copy = 0;
592            byte[] buffer = new byte[2048];
593            while (length > 0) {
594                int read = in.read(buffer, 0, (int) Math.min(buffer.length, length));
595                if (read <= 0) {
596                    break;
597                }
598                copy += read;
599                length -= read;
600                out.write(buffer, 0, read);
601            }
602            return copy;
603        }
604    
605        /**
606         * Copy file.
607         * @param src source file
608         * @param dest destination file
609         * @return how much bytes were copied.
610         * @throws IOException
611         */
612        public static long copy(File src, File dest) throws IOException {
613            InputStream in = new FileInputStream(src);
614            OutputStream out = new FileOutputStream(dest);
615            try {
616                return copy(in, out);
617            } finally {
618                IOutils.closeStream(in);
619                IOutils.closeStream(out);
620            }
621        }
622    
623        /**
624         * copy data from <code>in</code> to <code>out</code>
625         * @param in source InputStream
626         * @param out destination OutputStream
627         * @return how much bytes were copied.
628         * @throws IOException
629         */
630        public static long copy(InputStream in, OutputStream out) throws IOException {
631            long copy = 0;
632            byte[] buffer = new byte[2048];
633            while (true) {
634                int read = in.read(buffer);
635                if (read <= 0) {
636                    break;
637                }
638                copy += read;
639                out.write(buffer, 0, read);
640            }
641            return copy;
642        }
643    
644        /**
645         * copy data from source to destination stream
646         * @param in source stream
647         * @param out destination stream
648         * @throws IOException
649         * @return amount of copied bytes
650         */
651        public static long copy(InputStream in, DataOutput out) throws IOException {
652            long copy = 0;
653            byte[] buffer = new byte[2048];
654            while (true) {
655                int read = in.read(buffer);
656                if (read <= 0) {
657                    break;
658                }
659                copy += read;
660                out.write(buffer, 0, read);
661            }
662            return copy;
663        }
664    
665        /**
666         * copy data from <code>in</code> to <code>out</code>
667         * @param in source RandomAccessRO
668         * @param offset offset in <code>in</code>
669         * @param out destination OutputStream
670         * @throws IOException
671         */
672        public static long copy(RandomAccessInput in, long offset, OutputStream out) throws IOException {
673            long copy = 0;
674            byte[] buffer = new byte[2048];
675            in.seek(offset);
676            while (true) {
677                int read = in.read(buffer);
678                if (read <= 0) {
679                    break;
680                }
681                copy += read;
682                out.write(buffer, 0, read);
683            }
684            return copy;
685        }
686    
687        /**
688         * copy data from source to destination stream
689         * @param in source stream
690         * @param offset offset in source stream
691         * @param out destination stream
692         * @throws IOException
693         * @return how much bytes was copied
694         */
695        public static long copy(RandomAccessInput in, long offset, DataOutput out) throws IOException {
696            long copy = 0;
697            byte[] buffer = new byte[2048];
698            in.seek(offset);
699            while (true) {
700                int read = in.read(buffer);
701                if (read <= 0) {
702                    break;
703                }
704                copy += read;
705                out.write(buffer, 0, read);
706            }
707            return copy;
708        }
709    
710        /**
711         * copy data from source to destination stream
712         * @param offset offset in source stream
713         * @param length amount of bytes to copy
714         * @param in source stream
715         * @param out destination stream
716         * @throws IOException
717         */
718        public static long copy(long offset, long length, RandomAccessInput in, OutputStream out) throws IOException {
719            long copy = 0;
720            byte[] buffer = new byte[2048];
721            in.seek(offset);
722            while (length > 0) {
723                int read = in.read(buffer, 0, (int) Math.min(buffer.length, length));
724                if (read <= 0) {
725                    break;
726                }
727                copy += read;
728                length -= read;
729                out.write(buffer, 0, read);
730            }
731            return copy;
732        }
733    
734        /**
735         * copy data from source to destination stream
736         * @param offset offset in source stream
737         * @param length amount of bytes to copy
738         * @param in source stream
739         * @param out destination stream
740         * @throws IOException
741         */
742        public static long copy(long offset, long length, RandomAccessInput in, DataOutput out) throws IOException {
743            long copy = 0;
744            byte[] buffer = new byte[2048];
745            in.seek(offset);
746            while (length > 0) {
747                int read = in.read(buffer, 0, (int) Math.min(buffer.length, length));
748                if (read <= 0) {
749                    break;
750                }
751                copy += read;
752                length -= read;
753                out.write(buffer, 0, read);
754            }
755            return copy;
756        }
757    
758        /**
759         * read big/little-endian short
760         */
761        public static int readShort(InputStream in, int byteOrder) throws IOException {
762            switch (byteOrder) {
763                case BIG_ENDIAN:
764                    return readShort4D(in);
765                case LITTLE_ENDIAN:
766                    return readShort49(in);
767                default:
768                    throw new IllegalArgumentException("" + byteOrder);
769            }
770        }
771    
772        public static int readShort(DataInput in, int byteOrder) throws IOException {
773            switch (byteOrder) {
774                case BIG_ENDIAN:
775                    return readShort4D(in);
776                case LITTLE_ENDIAN:
777                    return readShort49(in);
778                default:
779                    throw new IllegalArgumentException("" + byteOrder);
780            }
781        }
782    
783        /**
784         * read big/little-endian int
785         */
786        public static int readInt(InputStream in, int byteOrder) throws IOException {
787            switch (byteOrder) {
788                case BIG_ENDIAN:
789                    return readInt4D(in);
790                case LITTLE_ENDIAN:
791                    return readInt49(in);
792                default:
793                    throw new IllegalArgumentException("" + byteOrder);
794            }
795        }
796    
797        /**
798         * read big/little-endian int
799         */
800        public static int readInt(DataInput in, int byteOrder) throws IOException {
801            switch (byteOrder) {
802                case BIG_ENDIAN:
803                    return readInt4D(in);
804                case LITTLE_ENDIAN:
805                    return readInt49(in);
806                default:
807                    throw new IllegalArgumentException("" + byteOrder);
808            }
809        }
810    
811    
812    }