commit
ebf72c103e
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="var" path="JRE_LIB" rootpath="JRE_SRCROOT" sourcepath="JRE_SRC"/>
|
||||
<classpathentry kind="src" path="/JUnit"/>
|
||||
<classpathentry kind="lib" path="C:/Program Files/Eclipse 2.0/plugins/org.eclipse.swt.win32_2.0.2/ws/win32/swt.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
|
@ -0,0 +1,2 @@
|
|||
bin
|
||||
AppleCommander.preferences
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>AppleCommander</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>JUnit</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,21 @@
|
|||
Attach the following code to the header of all source files.
|
||||
|
||||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
|
@ -0,0 +1,270 @@
|
|||
The GNU General Public License (GPL)
|
||||
Version 2, June 1991
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to
|
||||
share and change it. By contrast, the GNU General Public License is
|
||||
intended to guarantee your freedom to share and change free software--to
|
||||
make sure the software is free for all its users. This General Public
|
||||
License applies to most of the Free Software Foundation's software and to
|
||||
any other program whose authors commit to using it. (Some other Free
|
||||
Software Foundation software is covered by the GNU Library General Public
|
||||
License instead.) You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price.
|
||||
Our General Public Licenses are designed to make sure that you have the
|
||||
freedom to distribute copies of free software (and charge for this service
|
||||
if you wish), that you receive source code or can get it if you want it,
|
||||
that you can change the software or use pieces of it in new free programs;
|
||||
and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to
|
||||
deny you these rights or to ask you to surrender the rights. These
|
||||
restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or
|
||||
for a fee, you must give the recipients all the rights that you have. You
|
||||
must make sure that they, too, receive or can get the source code. And you
|
||||
must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2)
|
||||
offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that
|
||||
everyone understands that there is no warranty for this free software. If
|
||||
the software is modified by someone else and passed on, we want its
|
||||
recipients to know that what they have is not the original, so that any
|
||||
problems introduced by others will not reflect on the original authors'
|
||||
reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We
|
||||
wish to avoid the danger that redistributors of a free program will
|
||||
individually obtain patent licenses, in effect making the program
|
||||
proprietary. To prevent this, we have made it clear that any patent must
|
||||
be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a
|
||||
notice placed by the copyright holder saying it may be distributed under
|
||||
the terms of this General Public License. The "Program", below, refers to
|
||||
any such program or work, and a "work based on the Program" means either
|
||||
the Program or any derivative work under copyright law: that is to say, a
|
||||
work containing the Program or a portion of it, either verbatim or with
|
||||
modifications and/or translated into another language. (Hereinafter,
|
||||
translation is included without limitation in the term "modification".)
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of running
|
||||
the Program is not restricted, and the output from the Program is covered
|
||||
only if its contents constitute a work based on the Program (independent
|
||||
of having been made by running the Program). Whether that is true depends
|
||||
on what theProgram does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source
|
||||
code as you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice and
|
||||
disclaimer of warranty; keep intact all the notices that refer to this
|
||||
License and to the absence of any warranty; and give any other recipients
|
||||
of the Program a copy of this License along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you
|
||||
may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it,
|
||||
thus forming a work based on the Program, and copy and distribute such
|
||||
modifications or work under the terms of Section 1 above, provided that
|
||||
you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices stating
|
||||
that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole
|
||||
or in part contains or is derived from the Program or any part thereof, to
|
||||
be licensed as a whole at no charge to all third parties under the terms
|
||||
of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run,
|
||||
you must cause it, when started running for such interactive use in the
|
||||
most ordinary way, to print or display an announcement including an
|
||||
appropriate copyright notice and a notice that there is no warranty (or
|
||||
else, saying that you provide a warranty) and that users may redistribute
|
||||
the program under these conditions, and telling the user how to view a
|
||||
copy of this License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on the
|
||||
Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable
|
||||
sections of that work are not derived from the Program, and can be
|
||||
reasonably considered independent and separate works in themselves, then
|
||||
this License, and its terms, do not apply to those sections when you
|
||||
distribute them as separate works. But when you distribute the same
|
||||
sections as part of a whole which is a work based on the Program, the
|
||||
distribution of the whole must be on the terms of this License, whose
|
||||
permissions for other licensees extend to the entire whole, and thus to
|
||||
each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest your
|
||||
rights to work written entirely by you; rather, the intent is to exercise
|
||||
the right to control the distribution of derivative or collective works
|
||||
based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of a
|
||||
storage or distribution medium does not bring the other work under the
|
||||
scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under
|
||||
Section 2) in object code or executable form under the terms of Sections 1
|
||||
and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source
|
||||
code, which must be distributed under the terms of Sections 1 and 2 above
|
||||
on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to
|
||||
give any third party, for a charge no more than your cost of physically
|
||||
performing source distribution, a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of Sections 1
|
||||
and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to
|
||||
distribute corresponding source code. (This alternative is allowed only
|
||||
for noncommercial distribution and only if you received the program in
|
||||
object code or executable form with such an offer, in accord with
|
||||
Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for making
|
||||
modifications to it. For an executable work, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the executable. However, as a special exception, the
|
||||
source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major components
|
||||
(compiler, kernel, and so on) of the operating system on which the
|
||||
executable runs, unless that component itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering access to
|
||||
copy from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place counts as distribution of the source code,
|
||||
even though third parties are not compelled to copy the source along with
|
||||
the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except
|
||||
as expressly provided under this License. Any attempt otherwise to copy,
|
||||
modify, sublicense or distribute the Program is void, and will
|
||||
automatically terminate your rights under this License. However, parties
|
||||
who have received copies, or rights, from you under this License will not
|
||||
have their licenses terminated so long as such parties remain in full
|
||||
compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not signed
|
||||
it. However, nothing else grants you permission to modify or distribute
|
||||
the Program or its derivative works. These actions are prohibited by law
|
||||
if you do not accept this License. Therefore, by modifying or distributing
|
||||
the Program (or any work based on the Program), you indicate your
|
||||
acceptance of this License to do so, and all its terms and conditions for
|
||||
copying, distributing or modifying the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the original
|
||||
licensor to copy, distribute or modify the Program subject to these terms
|
||||
and conditions. You may not impose any further restrictions on the
|
||||
recipients' exercise of the rights granted herein. You are not responsible
|
||||
for enforcing compliance by third parties to this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot distribute
|
||||
so as to satisfy simultaneously your obligations under this License and
|
||||
any other pertinent obligations, then as a consequence you may not
|
||||
distribute the Program at all. For example, if a patent license would not
|
||||
permit royalty-free redistribution of the Program by all those who receive
|
||||
copies directly or indirectly through you, then the only way you could
|
||||
satisfy both it and this License would be to refrain entirely from
|
||||
distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any such
|
||||
claims; this section has the sole purpose of protecting the integrity of
|
||||
the free software distribution system, which is implemented by public
|
||||
license practices. Many people have made generous contributions to the
|
||||
wide range of software distributed through that system in reliance on
|
||||
consistent application of that system; it is up to the author/donor to
|
||||
decide if he or she is willing to distribute software through any other
|
||||
system and a licensee cannot impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to be a
|
||||
consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain
|
||||
countries either by patents or by copyrighted interfaces, the original
|
||||
copyright holder who places the Program under this License may add an
|
||||
explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of
|
||||
the General Public License from time to time. Such new versions will be
|
||||
similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free
|
||||
Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals of
|
||||
preserving the free status of all derivatives of our free software and of
|
||||
promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT
|
||||
LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
|
||||
SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
|
||||
WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Manifest-Version: 1.0
|
||||
Class-Path: swt.jar
|
||||
Main-Class: com.webcodepro.applecommander.ui.AppleCommander
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
/**
|
||||
* This class contains helper methods for dealing with Apple2 data.
|
||||
* <p>
|
||||
* Date created: Oct 5, 2002 4:16:16 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class AppleUtil {
|
||||
|
||||
/**
|
||||
* Compute the value of a word.
|
||||
* Pulls value from buffer given the offset.
|
||||
* A word is two bytes, in standard Apple LO/HI format.
|
||||
*/
|
||||
public static int getWordValue(byte[] buffer, int offset) {
|
||||
return getWordValue(buffer[offset], buffer[offset+1]);
|
||||
}
|
||||
/**
|
||||
* Compute the value of a word.
|
||||
*/
|
||||
public static int getWordValue(byte low, byte high) {
|
||||
return getUnsignedByte(low) + getUnsignedByte(high)*256;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the value of a 3 byte value. This may be ProDOS specific.
|
||||
* Pulls value from buffer given the offset.
|
||||
* Stored in standard Apple LO/HI format.
|
||||
*/
|
||||
public static int get3ByteValue(byte[] buffer, int offset) {
|
||||
return getUnsignedByte(buffer[offset])
|
||||
+ getUnsignedByte(buffer[offset+1])*256
|
||||
+ getUnsignedByte(buffer[offset+2])*65536;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract out an unsigned byte as an int.
|
||||
* All Java bytes are signed; need to convert to an int
|
||||
* and remove the sign.
|
||||
*/
|
||||
public static int getUnsignedByte(byte value) {
|
||||
return (int) value & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of bits set in a byte.
|
||||
*/
|
||||
public static int getBitCount(byte byt) {
|
||||
int count = 0;
|
||||
for (int ix=0; ix<8; ix++) {
|
||||
if (isBitSet(byt, ix)) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a specific bit is set.
|
||||
*/
|
||||
public static boolean isBitSet(byte byt, int bit) {
|
||||
byte[] masks = { (byte)0x01, (byte)0x02,(byte)0x04, (byte)0x08,
|
||||
(byte)0x10, (byte)0x20, (byte)0x40, (byte)0x80 };
|
||||
return (byt & masks[bit]) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a string from the buffer.
|
||||
*/
|
||||
public static String getString(byte[] buffer, int offset, int length) {
|
||||
byte[] value = new byte[length];
|
||||
for (int i=0; i<length; i++) {
|
||||
byte ch = buffer[offset+i];
|
||||
ch &= 0x7f;
|
||||
value[i] = ch;
|
||||
}
|
||||
return new String(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a Pascal string from the buffer.
|
||||
*/
|
||||
public static String getPascalString(byte[] buffer, int offset) {
|
||||
int length = getUnsignedByte(buffer[offset]);
|
||||
return getString(buffer, offset+1, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a Pascal date from the buffer.
|
||||
*/
|
||||
public static Date getPascalDate(byte[] buffer, int offset) {
|
||||
int pascalDate = getWordValue(buffer, offset);
|
||||
int month = pascalDate & 0x000f;
|
||||
int day = (pascalDate & 0x00f0) >> 4;
|
||||
int year = (pascalDate & 0xff00) >> 8;
|
||||
if (year < 50) year+= 2000;
|
||||
if (year < 100) year+= 1900;
|
||||
GregorianCalendar gc = new GregorianCalendar(year, month, day);
|
||||
return gc.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a ProDOS string from the buffer.
|
||||
*/
|
||||
public static String getProdosString(byte[] buffer, int offset) {
|
||||
int length = getUnsignedByte(buffer[offset]) & 0x0f;
|
||||
return getString(buffer, offset+1, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a byte value as hexidecimal.
|
||||
*/
|
||||
public static String getFormattedByte(int byt) {
|
||||
String[] values = { "0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"8", "9", "A", "B", "C", "D", "E", "F" };
|
||||
int byt1 = byt & 0x0f;
|
||||
int byt2 = (byt & 0xf0) >> 4;
|
||||
return values[byt2] + values[byt1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a word value as hexidecimal.
|
||||
*/
|
||||
public static String getFormattedWord(int word) {
|
||||
return getFormattedByte((word & 0xff00) >> 8)
|
||||
+ getFormattedByte(word & 0x00ff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a ProDOS date from the buffer.
|
||||
*/
|
||||
public static Date getProdosDate(byte[] buffer, int offset) {
|
||||
int ymd = getWordValue(buffer, offset);
|
||||
if (ymd == 0) return null;
|
||||
int hm = getWordValue(buffer, offset+2);
|
||||
|
||||
int day = ymd & 0x001f; // bits 0-4
|
||||
int month = (ymd & 0x01e0) >> 5; // bits 5-8
|
||||
int year = (ymd & 0xfe00) >> 9; // bits 9-15
|
||||
int minute = hm & 0x003f; // bits 0-5
|
||||
int hour = (hm & 0x1f00) >> 8; // bits 8-12
|
||||
|
||||
if (year < 50) year+= 2000;
|
||||
if (year < 100) year+= 1900;
|
||||
|
||||
GregorianCalendar gc = new GregorianCalendar(year, month, day, hour, minute);
|
||||
return gc.getTime();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Extract the contents of an AWP (AppleWorks word processor) document and
|
||||
* convert to a text format.
|
||||
* See format documentation at:
|
||||
* http://www.gno.org/pub/apple2/doc/apple/filetypes/ftn.1a.xxxx
|
||||
* <p>
|
||||
* Date created: Nov 15, 2002 3:55:21 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class AppleWorksWordProcessorFileFilter implements FileFilter {
|
||||
public static final int RENDER_AS_TEXT = 0;
|
||||
public static final int RENDER_AS_HTML = 1;
|
||||
private int rendering = RENDER_AS_TEXT;
|
||||
/**
|
||||
* Constructor for AppleWorksWordProcessorFileFilter.
|
||||
*/
|
||||
public AppleWorksWordProcessorFileFilter() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Process the given FileEntry and return a byte array with filtered data.
|
||||
* @see com.webcodepro.applecommander.storage.FileFilter#filter(FileEntry)
|
||||
*/
|
||||
public byte[] filter(FileEntry fileEntry) {
|
||||
byte[] fileData = fileEntry.getFileData();
|
||||
if (fileData[4] != 0x4f) return null; // not an AWP file!
|
||||
ByteArrayOutputStream byteArray = new ByteArrayOutputStream(fileData.length);
|
||||
PrintWriter printWriter = new PrintWriter(byteArray, true);
|
||||
if (isHtmlRendering()) {
|
||||
printWriter.println("<html><style>BODY { font-family: monospace; }</style><body>");
|
||||
}
|
||||
boolean version3 = (fileData[183] != 0);
|
||||
int offset = 300 + (version3 ? 2 : 0); // version 3.0's first line record is invalid
|
||||
while (offset < fileData.length) {
|
||||
int byte0 = AppleUtil.getUnsignedByte(fileData[offset++]);
|
||||
int byte1 = AppleUtil.getUnsignedByte(fileData[offset++]);
|
||||
|
||||
if (byte0 == 0xff && byte1 == 0xff) { // end of file
|
||||
break;
|
||||
} else if (byte1 == 0xd0) { // Carriage return line records
|
||||
handleReturn(printWriter);
|
||||
} else if (byte1 > 0xd0) { // Command line records
|
||||
if (isHtmlRendering()) {
|
||||
offset = handleCommandRecordAsHtml(byte0, byte1, printWriter, offset);
|
||||
}
|
||||
} else { // Text records (assumed)
|
||||
offset = handleTextRecord(fileData, printWriter, offset);
|
||||
}
|
||||
}
|
||||
if (isHtmlRendering()) {
|
||||
printWriter.println("</body></html>");
|
||||
}
|
||||
return byteArray.toByteArray();
|
||||
}
|
||||
/**
|
||||
* Deal with an individual text record.
|
||||
*/
|
||||
protected int handleTextRecord(byte[] fileData, PrintWriter printWriter, int offset) {
|
||||
int byte2 = AppleUtil.getUnsignedByte(fileData[offset++]);
|
||||
int byte3 = AppleUtil.getUnsignedByte(fileData[offset++]);
|
||||
boolean addReturn = (byte3 >= 0x80);
|
||||
int length = (byte3 & 0x7f);
|
||||
while (length > 0) {
|
||||
byte ch = fileData[offset++];
|
||||
length--;
|
||||
if (ch < 0x20) { // special formatting character
|
||||
if (isHtmlRendering()) handleSpecialCodesAsHtml(printWriter, ch);
|
||||
} else {
|
||||
if (isHtmlRendering() && ch == ' ') {
|
||||
int extraSpaces = 0;
|
||||
while (fileData[offset+extraSpaces] == ' ') {
|
||||
extraSpaces++;
|
||||
}
|
||||
if (extraSpaces > 0) {
|
||||
printWriter.print(" ");
|
||||
while (fileData[offset] == ' ') {
|
||||
offset++;
|
||||
length--;
|
||||
printWriter.print(" ");
|
||||
}
|
||||
} else {
|
||||
printWriter.print((char)ch);
|
||||
}
|
||||
} else {
|
||||
printWriter.print((char)ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addReturn) handleReturn(printWriter);
|
||||
return offset;
|
||||
}
|
||||
/**
|
||||
* Deal with carriage-return.
|
||||
*/
|
||||
protected void handleReturn(PrintWriter printWriter) {
|
||||
if (isHtmlRendering()) printWriter.println("<br>");
|
||||
else printWriter.println();
|
||||
}
|
||||
/**
|
||||
* Process special coding of a text record.
|
||||
*/
|
||||
protected void handleSpecialCodesAsHtml(PrintWriter printWriter, byte ch) {
|
||||
switch (ch) {
|
||||
case 0x01: printWriter.print("<b>");
|
||||
break;
|
||||
case 0x02: printWriter.print("</b>");
|
||||
break;
|
||||
case 0x03: printWriter.print("<sup>");
|
||||
break;
|
||||
case 0x04: printWriter.print("</sup>");
|
||||
break;
|
||||
case 0x05: printWriter.print("<sub>");
|
||||
break;
|
||||
case 0x06: printWriter.print("</sub>");
|
||||
break;
|
||||
case 0x07: printWriter.print("<u>");
|
||||
break;
|
||||
case 0x08: printWriter.print("</u>");
|
||||
break;
|
||||
case 0x09: printWriter.print("[Page#]");
|
||||
break;
|
||||
case 0x0b: printWriter.print(" ");
|
||||
break;
|
||||
case 0x0e: SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yy");
|
||||
printWriter.print(dateFormat.format(new Date()));
|
||||
break;
|
||||
case 0x0f: SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
printWriter.print(timeFormat.format(new Date()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deal with an individual command line record.
|
||||
*/
|
||||
protected int handleCommandRecordAsHtml(int byte0, int byte1,
|
||||
PrintWriter printWriter, int offset) {
|
||||
|
||||
switch (byte1) {
|
||||
case 0xd7: printWriter.println("<style>BODY: text-align: right;</style>");
|
||||
break;
|
||||
case 0xdf: printWriter.println("<style>BODY: text-align: justify;</style>");
|
||||
break;
|
||||
case 0xe0: printWriter.println("<style>BODY: text-align: left;</style>");
|
||||
break;
|
||||
case 0xe1: printWriter.println("<style>BODY: text-align: center;</style>");
|
||||
break;
|
||||
case 0xee: for (int i=0; i<byte0; i++) {
|
||||
printWriter.println("<br>");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
/**
|
||||
* Give suggested file name.
|
||||
* @see com.webcodepro.applecommander.storage.FileFilter#getSuggestedFileName(FileEntry)
|
||||
*/
|
||||
public String getSuggestedFileName(FileEntry fileEntry) {
|
||||
String fileName = fileEntry.getFilename().trim();
|
||||
String extension = ".txt";
|
||||
if (isHtmlRendering()) extension = ".html";
|
||||
|
||||
if (!fileName.toLowerCase().endsWith(extension)) {
|
||||
fileName = fileName + extension;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
/**
|
||||
* Set the rendering method.
|
||||
*/
|
||||
public void setRendering(int rendering) {
|
||||
this.rendering = rendering;
|
||||
}
|
||||
/**
|
||||
* Indicates if this is a text rendering.
|
||||
*/
|
||||
public boolean isTextRendering() {
|
||||
return rendering == RENDER_AS_TEXT;
|
||||
}
|
||||
/**
|
||||
* Indicates if this is an HTML rendering.
|
||||
*/
|
||||
public boolean isHtmlRendering() {
|
||||
return rendering == RENDER_AS_HTML;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Filter the given file as an Applesoft file.
|
||||
* <p>
|
||||
* Applesoft memory format:<br>
|
||||
* [Line]<br>
|
||||
* ...
|
||||
* [Line]<br>
|
||||
* <br>
|
||||
* where <Line> is:<br>
|
||||
* [Next addr - $0000 is end of program] (word)<br>
|
||||
* [Line no] (word)<br>
|
||||
* [Tokens and/or characters]<br>
|
||||
* [End-of-line marker: $00 bytes]
|
||||
* <p>
|
||||
* Date created: Nov 2, 2002 10:04:10 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class ApplesoftFileFilter implements FileFilter {
|
||||
private static String tokens[] = { // starts at $80
|
||||
" END ", " FOR ", " NEXT ", " DATA ", " INPUT ", " DEL ",
|
||||
" DIM ", " READ ", " GR ", " TEXT ", " PR# ", " IN# ",
|
||||
" CALL ", " PLOT ", " HLIN ", " VLIN ", " HGR2 ", " HGR ",
|
||||
" HCOLOR= ", " HPLOT ", " DRAW ", " XDRAW ", " HTAB ", " HOME ",
|
||||
" ROT= ", " SCALE= ", " SHLOAD ", " TRACE ", " NOTRACE ", " NORMAL ",
|
||||
" INVERSE ", " FLASH ", " COLOR= ", " POP ", " VTAB ", " HIMEM: ",
|
||||
" LOMEM: ", " ONERR ", " RESUME ", " RECALL ", " STORE ", " SPEED= ",
|
||||
" LET ", " GOTO ", " RUN ", " IF ", " RESTORE ", " & ",
|
||||
" GOSUB ", " RETURN ", " REM ", " STOP ", " ON ", " WAIT ",
|
||||
" LOAD ", " SAVE ", " DEF ", " POKE ", " PRINT ", " CONT ",
|
||||
" LIST ", " CLEAR ", " GET ", " NEW ", " TAB( ", " TO ",
|
||||
" FN ", " SPC( ", " THEN ", " AT ", " NOT ", " STEP ",
|
||||
" +", " -", " *", "/", " ^", " AND ",
|
||||
" OR ", " >", " =", " <", " SGN", " INT",
|
||||
" ABS", " USR", " FRE", " SCRN( ", " PDL", " POS",
|
||||
" SQR", " RND", " LOG", " EXP", " COS", " SIN",
|
||||
" TAN", " ATN", " PEEK", " LEN", " STR$", " VAL",
|
||||
" ASC", " CHR$", " LEFT$", " RIGHT$", " MID$ " };
|
||||
|
||||
/**
|
||||
* Constructor for ApplesoftFileFilter.
|
||||
*/
|
||||
public ApplesoftFileFilter() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given FileEntry and return a text image of the Applesoft file.
|
||||
* @see com.webcodepro.applecommander.storage.FileFilter#filter(FileEntry)
|
||||
*/
|
||||
public byte[] filter(FileEntry fileEntry) {
|
||||
byte[] fileData = fileEntry.getFileData();
|
||||
int offset = 0;
|
||||
ByteArrayOutputStream byteArray = new ByteArrayOutputStream(fileData.length * 2);
|
||||
PrintWriter printWriter = new PrintWriter(byteArray, true);
|
||||
while (offset < fileData.length) {
|
||||
int nextAddress = AppleUtil.getWordValue(fileData, offset);
|
||||
if (nextAddress == 0) break; // next address of 0 indicates end of program
|
||||
offset+= 2;
|
||||
int lineNumber = AppleUtil.getWordValue(fileData, offset);
|
||||
offset+= 2;
|
||||
printWriter.print(lineNumber);
|
||||
printWriter.print(' ');
|
||||
while (fileData[offset] != 0) {
|
||||
byte byt = fileData[offset++];
|
||||
if ((byt & 0x80) != 0) {
|
||||
int token = AppleUtil.getUnsignedByte(byt) - 0x80;
|
||||
if (token >= tokens.length) {
|
||||
printWriter.print("<UNKNOWN TOKEN>");
|
||||
} else {
|
||||
String tokenString = tokens[token];
|
||||
printWriter.print(tokenString);
|
||||
}
|
||||
} else {
|
||||
char ch = (char)byt;
|
||||
if (ch < 0x20) {
|
||||
printWriter.print("<CTRL-");
|
||||
printWriter.print((char)('@' + ch));
|
||||
printWriter.print(">");
|
||||
} else {
|
||||
printWriter.print(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
printWriter.println();
|
||||
offset++; // skip to next line
|
||||
}
|
||||
return byteArray.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Give suggested file name.
|
||||
*/
|
||||
public String getSuggestedFileName(FileEntry fileEntry) {
|
||||
String fileName = fileEntry.getFilename().trim();
|
||||
if (!fileName.toLowerCase().endsWith(".bas")) {
|
||||
fileName = fileName + ".bas";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
/**
|
||||
* Filter the given file data to be the appropriate length.
|
||||
* <p>
|
||||
* Date created: Nov 2, 2002 9:07:52 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class BinaryFileFilter implements FileFilter {
|
||||
/**
|
||||
* Constructor for BinaryFileFilter.
|
||||
*/
|
||||
public BinaryFileFilter() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given FileEntry and return a byte array with filtered data.
|
||||
* @see com.webcodepro.applecommander.storage.FileFilter#filter(byte[])
|
||||
*/
|
||||
public byte[] filter(FileEntry fileEntry) {
|
||||
return fileEntry.getFileData(); // should be nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Give suggested file name.
|
||||
*/
|
||||
public String getSuggestedFileName(FileEntry fileEntry) {
|
||||
String fileName = fileEntry.getFilename().trim();
|
||||
if (!fileName.toLowerCase().endsWith(".dump")) {
|
||||
fileName = fileName + ".dump";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Abstract representation of an Apple2 disk (floppy, 800k, hard disk).
|
||||
* <p>
|
||||
* Date created: Oct 3, 2002 10:59:47 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class Disk {
|
||||
/**
|
||||
* Specifies a filter to be used in determining filetypes which are supported.
|
||||
* This works from a file extension, so it may or may not apply to the Macintosh.
|
||||
*/
|
||||
public class FilenameFilter {
|
||||
private String names;
|
||||
private String extensions;
|
||||
public FilenameFilter(String names, String extensions) {
|
||||
this.names = names;
|
||||
this.extensions = extensions;
|
||||
}
|
||||
public String getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
public String getNames() {
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int BLOCK_SIZE = 512;
|
||||
public static final int SECTOR_SIZE = 256;
|
||||
public static final int APPLE_140KB_DISK = 143360;
|
||||
public static final int APPLE_800KB_DISK = 819200;
|
||||
public static final int APPLE_800KB_2IMG_DISK = APPLE_800KB_DISK + 0x40;
|
||||
|
||||
private static FilenameFilter[] filenameFilters;
|
||||
private byte[] diskImage;
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* Get the supported file filters supported by the Disk interface.
|
||||
* This is due to the fact that FilenameFilter is an innerclass of Disk -
|
||||
* without an instance of the class, the filters cannot be created.
|
||||
*/
|
||||
public static FilenameFilter[] getFilenameFilters() {
|
||||
if (filenameFilters == null) {
|
||||
new Disk();
|
||||
}
|
||||
return filenameFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a Disk - used only to generate FilenameFilter objects.
|
||||
*/
|
||||
private Disk() {
|
||||
filenameFilters = new FilenameFilter[] {
|
||||
new FilenameFilter("All Emulator Images",
|
||||
"*.do; *.dsk; *.po; *.2mg; *.2img; *.hdv; *.do.gz; *.dsk.gz; *.po.gz; *.2mg.gz; *.2img.gz"),
|
||||
new FilenameFilter("140K DOS 3.3 Ordered Images (*.do, *.dsk)",
|
||||
"*.do; *.dsk; *.do.gz; *.dsk.gz"),
|
||||
new FilenameFilter("140K ProDOS Ordered Images (*.po)",
|
||||
"*.po; *.po.gz"),
|
||||
new FilenameFilter("800K ProDOS Ordered Images (*.2mg, *.2img)",
|
||||
"*.2mg; *.2img; *.2mg.gz, *.2img.gz"),
|
||||
new FilenameFilter("ApplePC Hard Disk Images (*.hdv)",
|
||||
"*.hdv"),
|
||||
new FilenameFilter("All Compressed Images",
|
||||
"*.do.gz; *.dsk.gz; *.po.gz; *.2mg.gz; *.2img.gz"),
|
||||
new FilenameFilter("All Files",
|
||||
"*.*")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Disk with the given byte array.
|
||||
*/
|
||||
protected Disk(String filename, byte[] diskImage) {
|
||||
this.diskImage = diskImage;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Disk and load the specified file.
|
||||
* Read in the entire contents of the file.
|
||||
*/
|
||||
public Disk(String filename) throws IOException {
|
||||
this.filename = filename;
|
||||
InputStream input = new FileInputStream(filename);
|
||||
if (isCompressed()) {
|
||||
input = new GZIPInputStream(input);
|
||||
}
|
||||
int diskSize = APPLE_140KB_DISK;
|
||||
if (is2ImgOrder()) {
|
||||
diskSize = APPLE_800KB_2IMG_DISK;
|
||||
}
|
||||
ByteArrayOutputStream diskImageByteArray =
|
||||
new ByteArrayOutputStream(diskSize);
|
||||
byte[] data = new byte[1024];
|
||||
int bytes;
|
||||
while ((bytes = input.read(data)) > 0) {
|
||||
diskImageByteArray.write(data, 0, bytes);
|
||||
}
|
||||
input.close();
|
||||
this.diskImage = diskImageByteArray.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine type of disk, and return the appropriate
|
||||
* FormattedDisk object. Returns null if none are
|
||||
* recognized.
|
||||
*/
|
||||
public FormattedDisk getFormattedDisk() {
|
||||
if (isProdosFormat()) {
|
||||
return new ProdosFormatDisk(filename, diskImage);
|
||||
} else if (isDosFormat()) {
|
||||
return new DosFormatDisk(filename, diskImage);
|
||||
} else if (isPascalFormat()) {
|
||||
return new PascalFormatDisk(filename, diskImage);
|
||||
} else if (isRdosFormat()) {
|
||||
return new RdosFormatDisk(filename, diskImage);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the diskImage.
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getDiskImage() {
|
||||
return diskImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a portion of the disk image.
|
||||
*/
|
||||
public byte[] readBytes(int start, int length) {
|
||||
byte[] buffer = new byte[length];
|
||||
System.arraycopy(diskImage, start + (is2ImgOrder() ? 0x40 : 0), buffer, 0, length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename.
|
||||
* @return String
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this disk is GZIP compressed.
|
||||
*/
|
||||
public boolean isCompressed() {
|
||||
return filename.toLowerCase().endsWith(".gz");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this disk is ProDOS ordered (beginning with block 0).
|
||||
*/
|
||||
public boolean isProdosOrder() {
|
||||
return filename.toLowerCase().endsWith(".po")
|
||||
|| filename.toLowerCase().endsWith(".po.gz")
|
||||
|| is2ImgOrder()
|
||||
|| filename.toLowerCase().endsWith(".hdv");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this disk is DOS ordered (T0,S0 - T35,S15).
|
||||
*/
|
||||
public boolean isDosOrder() {
|
||||
return filename.toLowerCase().endsWith(".do")
|
||||
|| filename.toLowerCase().endsWith(".do.gz")
|
||||
|| filename.toLowerCase().endsWith(".dsk")
|
||||
|| filename.toLowerCase().endsWith(".dsk.gz");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this disk is a 2IMG disk.
|
||||
* This is ProDOS ordered, but with a header on the disk.
|
||||
*/
|
||||
public boolean is2ImgOrder() {
|
||||
return filename.toLowerCase().endsWith(".2img")
|
||||
|| filename.toLowerCase().endsWith(".2img.gz")
|
||||
|| filename.toLowerCase().endsWith(".2mg")
|
||||
|| filename.toLowerCase().endsWith(".2mg.gz");
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the size of this disk.
|
||||
*/
|
||||
public int getPhysicalSize() {
|
||||
return diskImage.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block from the disk image.
|
||||
*/
|
||||
public byte[] readBlock(int block) {
|
||||
if (block * BLOCK_SIZE > getPhysicalSize()) {
|
||||
return null;
|
||||
} else {
|
||||
if (isProdosOrder()) {
|
||||
return readBytes(block*BLOCK_SIZE, BLOCK_SIZE);
|
||||
} else if (isDosOrder()) {
|
||||
int[] sectorMapping1 = { 0, 13, 11, 9, 7, 5, 3, 1 };
|
||||
int[] sectorMapping2 = { 14, 12, 10, 8, 6, 4, 2, 15 };
|
||||
int track = block / 8;
|
||||
int sectorOffset = block % 8;
|
||||
int sector1 = sectorMapping1[sectorOffset];
|
||||
int sector2 = sectorMapping2[sectorOffset];
|
||||
int physicalLocation1 = (track * 16 + sector1) * SECTOR_SIZE;
|
||||
int physicalLocation2 = (track * 16 + sector2) * SECTOR_SIZE;
|
||||
byte[] data = new byte[BLOCK_SIZE];
|
||||
System.arraycopy(readBytes(physicalLocation1, SECTOR_SIZE),
|
||||
0, data, 0, SECTOR_SIZE);
|
||||
System.arraycopy(readBytes(physicalLocation2, SECTOR_SIZE),
|
||||
0, data, SECTOR_SIZE, SECTOR_SIZE);
|
||||
return data;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the specified sector.
|
||||
*/
|
||||
public byte[] readSector(int track, int sector) {
|
||||
if ((track * 16 + sector) * SECTOR_SIZE > getPhysicalSize()) {
|
||||
return null;
|
||||
} else if (isProdosOrder()) {
|
||||
// what block a sector belongs to:
|
||||
int[] blockInterleave = { 0, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 7 };
|
||||
// where in that block a sector resides:
|
||||
int[] blockOffsets = { 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1 };
|
||||
return readBytes(
|
||||
((track * 8) + blockInterleave[sector]) * BLOCK_SIZE
|
||||
+ blockOffsets[sector] * SECTOR_SIZE, SECTOR_SIZE);
|
||||
} else if (isDosOrder()) {
|
||||
return readBytes((track * 16 + sector) * SECTOR_SIZE, SECTOR_SIZE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the disk format to see if this is a ProDOS formatted
|
||||
* disk.
|
||||
*/
|
||||
public boolean isProdosFormat() {
|
||||
byte[] prodosVolumeDirectory = readBlock(2);
|
||||
return prodosVolumeDirectory[0] == 0 &&
|
||||
prodosVolumeDirectory[1] == 0 &&
|
||||
(prodosVolumeDirectory[4]&0xf0) == 0xf0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the disk format to see if this is a DOS 3.3 formatted
|
||||
* disk.
|
||||
*/
|
||||
public boolean isDosFormat() {
|
||||
byte[] vtoc = readSector(17, 0);
|
||||
return vtoc[0x01] == 17 // expect catalog to start on track 17
|
||||
&& vtoc[0x02] == 15 // expect catalog to start on sector 15
|
||||
&& vtoc[0x03] == 3 // expect DOS release number of 3
|
||||
&& vtoc[0x27] == 122 // expect 122 tract/sector pairs per sector
|
||||
&& vtoc[0x34] == 35 // expect 35 tracks per disk (140KB disk only!)
|
||||
&& vtoc[0x35] == 16 // expect 16 sectors per disk (140KB disk only!)
|
||||
&& vtoc[0x36] == 0 // bytes per sector (low byte)
|
||||
&& vtoc[0x37] == 1; // bytes per sector (high byte)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the disk format to see if this is a Pascal formatted
|
||||
* disk.
|
||||
*/
|
||||
public boolean isPascalFormat() {
|
||||
byte[] directory = readBlock(2);
|
||||
return directory[0] == 0 && directory[1] == 0
|
||||
&& directory[2] == 6 && directory[3] == 0
|
||||
&& directory[4] == 0 && directory[5] == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the disk format to see if this is a RDOS formatted
|
||||
* disk.
|
||||
*/
|
||||
public boolean isRdosFormat() {
|
||||
byte[] block = readSector(0, 0x0d);
|
||||
String id = AppleUtil.getString(block, 0xe0, 4);
|
||||
return "RDOS".equals(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Helper class to load Apple2 disk images.
|
||||
* This class identifies the format, and the type of disk, loading the
|
||||
* appropriate disk management class.
|
||||
* <p>
|
||||
* Date created: Oct 3, 2002 10:54:34 PM
|
||||
* @author: Rob Greene
|
||||
* @deprecated
|
||||
*/
|
||||
public class DiskHelper {
|
||||
public static final int APPLE_140KB_DISK = 143360;
|
||||
public static final int APPLE_800KB_DISK = 819200;
|
||||
public static final int APPLE_800KB_2IMG_DISK = APPLE_800KB_DISK + 0x40;
|
||||
|
||||
/**
|
||||
* Load an Apple2 disk from a given filename.
|
||||
* Determine type of disk, load approparitely, and
|
||||
* construct the appropriate Disk object.
|
||||
*/
|
||||
public static FormattedDisk load(String filename) throws IOException {
|
||||
if (filename == null) return null;
|
||||
byte[] diskImage = loadDisk(filename);
|
||||
|
||||
Disk test = new Disk(filename, diskImage);
|
||||
if (test.isProdosFormat()) {
|
||||
return new ProdosFormatDisk(filename, diskImage);
|
||||
} else if (test.isDosFormat()) {
|
||||
return new DosFormatDisk(filename, diskImage);
|
||||
} else if (test.isPascalFormat()) {
|
||||
return new PascalFormatDisk(filename, diskImage);
|
||||
} else if (test.isRdosFormat()) {
|
||||
return new RdosFormatDisk(filename, diskImage);
|
||||
}
|
||||
|
||||
// FIXME: Should return unknown disk Disk
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in a disk in the same order as the image.
|
||||
* Disk itself will handle location translation.
|
||||
*/
|
||||
private static byte[] loadDisk(String filename) throws IOException {
|
||||
InputStream input = new FileInputStream(filename);
|
||||
if (filename.toLowerCase().endsWith(".gz")) {
|
||||
input = new GZIPInputStream(input);
|
||||
}
|
||||
int diskSize = APPLE_140KB_DISK;
|
||||
if (filename.toLowerCase().endsWith(".2img") || filename.toLowerCase().endsWith(".2mg")) {
|
||||
diskSize = APPLE_800KB_2IMG_DISK;
|
||||
}
|
||||
ByteArrayOutputStream diskImage =
|
||||
new ByteArrayOutputStream(diskSize);
|
||||
byte[] data = new byte[1024];
|
||||
int bytes;
|
||||
while ((bytes = input.read(data)) > 0) {
|
||||
diskImage.write(data, 0, bytes);
|
||||
}
|
||||
input.close();
|
||||
return diskImage.toByteArray();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a DOS file entry on disk.
|
||||
* <p>
|
||||
* Date created: Oct 4, 2002 5:15:25 PM
|
||||
* @author: Rob Greene
|
||||
*/
|
||||
public class DosFileEntry implements FileEntry {
|
||||
private byte[] fileEntry;
|
||||
private DosFormatDisk disk;
|
||||
|
||||
/**
|
||||
* Constructor for DosFileEntry.
|
||||
*/
|
||||
public DosFileEntry(byte[] fileEntry, DosFormatDisk disk) {
|
||||
super();
|
||||
this.fileEntry = fileEntry;
|
||||
this.disk = disk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this file.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#getFilename()
|
||||
*/
|
||||
public String getFilename() {
|
||||
byte[] filename = new byte[30];
|
||||
System.arraycopy(fileEntry, 3, filename, 0, filename.length);
|
||||
for (int i=0; i<filename.length; i++) {
|
||||
filename[i] &= 0x7f;
|
||||
}
|
||||
return new String(filename).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filetype of this file.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#getFiletype()
|
||||
*/
|
||||
public String getFiletype() {
|
||||
int filetype = (AppleUtil.getUnsignedByte(fileEntry[2]) & 0x7f);
|
||||
if (filetype == 0x00) return "T";
|
||||
// the "^" operator is exclusive or - used to ensure only that
|
||||
// bit was turned on. if others are turned on, fall through and
|
||||
// return a "?" as the file type
|
||||
if ((filetype ^ 0x01) == 0) return "I";
|
||||
if ((filetype ^ 0x02) == 0) return "A";
|
||||
if ((filetype ^ 0x04) == 0) return "B";
|
||||
if ((filetype ^ 0x08) == 0) return "S";
|
||||
if ((filetype ^ 0x10) == 0) return "R";
|
||||
if ((filetype ^ 0x20) == 0) return "a";
|
||||
if ((filetype ^ 0x40) == 0) return "b";
|
||||
return "?"; // should never occur (read the code!)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if this file is locked.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#isLocked()
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return (fileEntry[2] & 0x80) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the size of this file (in bytes).
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#getSize()
|
||||
*/
|
||||
public int getSize() {
|
||||
byte[] rawdata = null;
|
||||
if (!isDeleted()) {
|
||||
rawdata = disk.getFileData(this);
|
||||
}
|
||||
// default to nothing special, just compute from number of sectors
|
||||
int size = (getSectorsUsed()-1) * Disk.SECTOR_SIZE;
|
||||
if (rawdata != null) {
|
||||
if ("B".equals(getFiletype())) {
|
||||
// binary
|
||||
return AppleUtil.getWordValue(rawdata, 2);
|
||||
} else if ("A".equals(getFiletype()) || "I".equals(getFiletype())) {
|
||||
// applesoft, integer basic
|
||||
return AppleUtil.getWordValue(rawdata, 0);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of sectors used.
|
||||
*/
|
||||
public int getSectorsUsed() {
|
||||
return AppleUtil.getUnsignedByte(fileEntry[0x21])
|
||||
+ AppleUtil.getUnsignedByte(fileEntry[0x22])*16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if this is a directory file.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#isDirectory()
|
||||
*/
|
||||
public boolean isDirectory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of files in this directory.
|
||||
* Always returns null for DOS.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#getFiles()
|
||||
*/
|
||||
public List getFiles() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if this file has been deleted.
|
||||
* @see com.webcodepro.applecommander.storage.FileEntry#isDeleted()
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return AppleUtil.getUnsignedByte(fileEntry[0]) == 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standard file column header information.
|
||||
* This default implementation is intended only for standard mode.
|
||||
* displayMode is specified in FormattedDisk.
|
||||
*/
|
||||
public List getFileColumnData(int displayMode) {
|
||||
NumberFormat numberFormat = NumberFormat.getNumberInstance();
|
||||
|
||||
List list = new ArrayList();
|
||||
switch (displayMode) {
|
||||
case FormattedDisk.FILE_DISPLAY_NATIVE:
|
||||
list.add(isLocked() ? "*" : " ");
|
||||
list.add(getFiletype());
|
||||
numberFormat.setMinimumIntegerDigits(3);
|
||||
list.add(numberFormat.format(getSectorsUsed()));
|
||||
list.add(getFilename());
|
||||
break;
|
||||
case FormattedDisk.FILE_DISPLAY_DETAIL:
|
||||
list.add(isLocked() ? "*" : " ");
|
||||
list.add(getFiletype());
|
||||
list.add(getFilename());
|
||||
list.add(numberFormat.format(getSize( |